Browse Source

新增ant-vue 前端模块

pull/226/head
sxh 4 years ago
parent
commit
2cb3ab8799
  1. 28
      pom.xml
  2. 10
      src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
  3. 172
      src/main/java/com/genersoft/iot/vmp/common/ApiSaveConstant.java
  4. 95
      src/main/java/com/genersoft/iot/vmp/common/MyPageInfo.java
  5. 95
      src/main/java/com/genersoft/iot/vmp/common/Page.java
  6. 99
      src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
  7. 39
      src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
  8. 28
      src/main/java/com/genersoft/iot/vmp/common/reponse/ErrorResponseData.java
  9. 98
      src/main/java/com/genersoft/iot/vmp/common/reponse/ResponseData.java
  10. 15
      src/main/java/com/genersoft/iot/vmp/common/reponse/SuccessResponseData.java
  11. 96
      src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
  12. 42
      src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
  13. 222
      src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
  14. 191
      src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
  15. 90
      src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java
  16. 96
      src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java
  17. 10
      src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java
  18. 6
      src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
  19. 52
      src/main/java/com/genersoft/iot/vmp/conf/Swagger3Config.java
  20. 96
      src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java
  21. 25
      src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java
  22. 24
      src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java
  23. 28
      src/main/java/com/genersoft/iot/vmp/conf/WebConfig.java
  24. 5
      src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
  25. 2
      src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
  26. 15
      src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
  27. 7
      src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
  28. 215
      src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
  29. 9
      src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
  30. 16
      src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
  31. 60
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  32. 26
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
  33. 9
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java
  34. 15
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java
  35. 13
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
  36. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
  37. 13
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java
  38. 68
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java
  39. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java
  40. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java
  41. 86
      src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
  42. 6
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java
  43. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java
  44. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java
  45. 7
      src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java
  46. 2
      src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java
  47. 14
      src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java
  48. 6
      src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java
  49. 28
      src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java
  50. 140
      src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java
  51. 101
      src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java
  52. 101
      src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
  53. 229
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
  54. 160
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
  55. 21
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java
  56. 71
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
  57. 28
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java
  58. 32
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
  59. 25
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java
  60. 59
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  61. 460
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
  62. 8
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
  63. 14
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java
  64. 23
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorAbstract.java
  65. 178
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java
  66. 251
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java
  67. 117
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
  68. 42
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java
  69. 835
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
  70. 2146
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/MessageRequestProcessor1.java
  71. 108
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java
  72. 396
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  73. 141
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java
  74. 23
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java
  75. 43
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
  76. 91
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java
  77. 21
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java
  78. 16
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java
  79. 114
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java
  80. 120
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java
  81. 63
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
  82. 74
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
  83. 103
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java
  84. 21
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java
  85. 120
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java
  86. 111
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceControlQueryMessageHandler.java
  87. 62
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java
  88. 75
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java
  89. 21
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java
  90. 58
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java
  91. 72
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java
  92. 182
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java
  93. 81
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java
  94. 58
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java
  95. 59
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java
  96. 103
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java
  97. 89
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java
  98. 103
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java
  99. 153
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
  100. 15
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java

28
pom.xml

@ -46,7 +46,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.build.timestamp.format>yyyyMMddHHmmss</maven.build.timestamp.format>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<jedis-version>3.1.0</jedis-version>
<!-- 依赖版本 -->
<pagehelper.version>5.2.0</pagehelper.version>
<snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
@ -65,6 +65,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
@ -74,6 +79,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis-version}</version>
</dependency>
<!-- druid数据库连接池 -->
<dependency>
@ -191,6 +201,16 @@
<version>1.12</version>
</dependency>
<!-- &lt;!&ndash; 检测文件编码 &ndash;&gt;-->
<!-- &lt;!&ndash; https://mvnrepository.com/artifact/cpdetector/cpdetector &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>cpdetector</groupId>-->
<!-- <artifactId>cpdetector</artifactId>-->
<!-- <version>1.0.8</version>-->
<!-- </dependency>-->
<!-- onvif协议栈 -->
<dependency>
<groupId>be.teletask</groupId>
@ -199,6 +219,12 @@
<scope>system</scope>
<systemPath>${project.basedir}/libs/onvif-java-1.0.2.jar</systemPath>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!-- <scope>test</scope>-->
</dependency>
</dependencies>

10
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@ -1,13 +1,17 @@
package com.genersoft.iot.vmp;
import java.util.logging.LogManager;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.oas.annotations.EnableOpenApi;
import java.util.logging.LogManager;
@ServletComponentScan("com.genersoft.iot.vmp.conf")
@SpringBootApplication
@EnableScheduling
@EnableOpenApi
public class VManageBootstrap extends LogManager {
private static String[] args;
@ -20,7 +24,7 @@ public class VManageBootstrap extends LogManager {
public static void restart() {
context.close();
VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
}
}

172
src/main/java/com/genersoft/iot/vmp/common/ApiSaveConstant.java

@ -0,0 +1,172 @@
package com.genersoft.iot.vmp.common;
public class ApiSaveConstant {
public static String getVal(String key) {
String[] keyItemArray = key.split("/");
if (keyItemArray.length <= 1 || !"api".equals(keyItemArray[1])) {
return null;
}
if (keyItemArray.length >= 4) {
switch (keyItemArray[2]) {
case "alarm":
if ("delete".equals(keyItemArray[3])) {
return "删除报警";
}
break;
case "device":
switch (keyItemArray[3]) {
case "config":
if (keyItemArray.length >= 5 && "basicParam".equals(keyItemArray[4])) {
return "[设备配置] 基本配置设置命令";
}
break;
case "control":
switch (keyItemArray[4]) {
case "teleboot":
return "[设备控制] 远程启动";
case "record":
return "[设备控制] 录像控制";
case "guard":
return "[设备控制] 布防/撤防命令";
case "reset_alarm":
return "[设备控制] 报警复位";
case "i_frame":
return "[设备控制] 强制关键帧";
case "home_position":
return "[设备控制] 看守位控制";
}
break;
case "query":
if (keyItemArray.length <= 5) return null;
switch (keyItemArray[4]) {
case "devices":
if (keyItemArray.length < 7) return null;
switch (keyItemArray[6]) {
case "sync":
return "[设备查询] 同步设备通道";
case "delete":
return "[设备查询] 移除设备";
}
break;
case "channel":
return "[设备查询] 更新通道信息";
case "transport":
return "[设备查询] 修改数据流传输模式";
}
break;
}
case "gbStream":
switch (keyItemArray[3]) {
case "del":
return "移除通道与国标的关联";
case "add":
return "添加通道与国标的关联";
}
break;
case "media":
break;
case "position":
if ("subscribe".equals(keyItemArray[3])) {
return "订阅位置信息";
}
break;
case "platform":
switch (keyItemArray[3]) {
case "save":
return "添加上级平台";
case "delete":
return "移除上级平台";
case "update_channel_for_gb":
return "向上级平台添加国标通道";
case "del_channel_for_gb":
return "从上级平台移除国标通道";
}
break;
case "platform_gb_stream":
break;
case "play":
switch (keyItemArray[3]) {
case "start":
return "开始点播";
case "stop":
return "停止点播";
case "convert":
return "转码";
case "convertStop":
return "结束转码";
case "broadcast":
return "语音广播";
}
break;
case "download":
switch (keyItemArray[3]) {
case "start":
return "开始历史媒体下载";
case "stop":
return "停止历史媒体下载";
}
break;
case "playback":
switch (keyItemArray[3]) {
case "start":
return "开始视频回放";
case "stop":
return "停止视频回放";
}
break;
case "ptz":
switch (keyItemArray[3]) {
case "control":
return "云台控制";
case "front_end_command":
return "通用前端控制命令";
}
break;
case "gb_record":
break;
case "onvif":
break;
case "server":
if ("restart".equals(keyItemArray[3])) {
return "重启流媒体服务";
}
break;
case "proxy":
switch (keyItemArray[3]) {
case "save":
return "保存代理";
case "del":
return "移除代理";
case "start":
return "启用代理";
case "stop":
return "停用代理";
}
break;
case "push":
switch (keyItemArray[3]) {
case "save_to_gb":
return "将推流添加到国标";
case "remove_form_gb":
return "将推流移出到国标";
}
break;
case "user":
switch (keyItemArray[3]) {
case "login":
return "登录";
case "changePassword":
return "修改密码";
case "add":
return "添加用户";
case "delete":
return "删除用户";
}
break;
}
}
return null;
}
}

95
src/main/java/com/genersoft/iot/vmp/common/MyPageInfo.java

@ -0,0 +1,95 @@
package com.genersoft.iot.vmp.common;
import java.util.ArrayList;
import java.util.List;
public class MyPageInfo<T> {
//当前页
private int pageNo;
//每页的数量
private int pageSize;
//当前页的数量
private int size;
//总页数
private int pages;
//总数
private int total;
private List<T> resultData;
private List<T> list;
public MyPageInfo(List<T> resultData) {
this.resultData = resultData;
}
public void startPage(int page, int count) {
if (page <= 0) page = 1;
this.pageNo = page;
this.pageSize = count;
this.total = resultData.size();
this.pages = total%count == 0 ? total/count : total/count + 1;
int fromIndx = (page - 1) * count;
if ( fromIndx > this.total - 1) {
this.list = new ArrayList<>();
this.size = 0;
return;
}
int toIndx = page * count;
if (toIndx > this.total) {
toIndx = this.total;
}
this.list = this.resultData.subList(fromIndx, toIndx);
this.size = this.list.size();
}
public int getPageNo() {
return pageNo;
}
public void setPageNo(int pageNo) {
this.pageNo = pageNo;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getPages() {
return pages;
}
public void setPages(int pages) {
this.pages = pages;
}
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public List<T> getList() {
return list;
}
public void setList(List<T> list) {
this.list = list;
}
}

95
src/main/java/com/genersoft/iot/vmp/common/Page.java

@ -0,0 +1,95 @@
package com.genersoft.iot.vmp.common;
import com.github.pagehelper.PageInfo;
import java.util.List;
public class Page<T> {
private Integer pageSize;
private Integer pageNo;
private Integer totalPage;
private Long totalCount;
private List<T> data;
public Page() {
}
public Page(Integer pageSize, Integer pageNo, Integer totalPage, Long totalCount, List<T> data) {
this.pageSize = pageSize;
this.pageNo = pageNo;
this.totalPage = totalPage;
this.totalCount = totalCount;
this.data = data;
}
public Page(PageInfo<T> pageInfo) {
Integer pageNo = pageInfo.getPageNum();
Integer pageSize = pageInfo.getPageSize();
Integer totalPage = pageInfo.getPages();
Long totalCount = pageInfo.getTotal();
List<T> data = pageInfo.getList();
setPageNo(pageNo);
setPageSize(pageSize);
setTotalPage(totalPage);
setTotalCount(totalCount);
setData(data);
}
public Page(MyPageInfo<T> myPageInfo){
Integer pageNo = myPageInfo.getPageNo();
Integer pageSize = myPageInfo.getPageSize();
Integer totalPage = myPageInfo.getPages();
int totalCount = myPageInfo.getTotal();
List<T> data = myPageInfo.getList();
setPageNo(pageNo);
setPageSize(pageSize);
setTotalPage(totalPage);
setTotalCount((long) totalCount);
setData(data);
}
public Integer getPageSize() {
return pageSize;
}
public void setPageSize(Integer pageSize) {
this.pageSize = pageSize;
}
public Integer getPageNo() {
return pageNo;
}
public void setPageNo(Integer pageNo) {
this.pageNo = pageNo;
}
public Integer getTotalPage() {
return totalPage;
}
public void setTotalPage(Integer totalPage) {
this.totalPage = totalPage;
}
public Long getTotalCount() {
return totalCount;
}
public void setTotalCount(Long totalCount) {
this.totalCount = totalCount;
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
}

99
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java

@ -9,16 +9,27 @@ public class StreamInfo {
private String deviceID;
private String channelId;
private String flv;
private String https_flv;
private String ws_flv;
private String wss_flv;
private String fmp4;
private String https_fmp4;
private String ws_fmp4;
private String wss_fmp4;
private String hls;
private String https_hls;
private String ws_hls;
private String wss_hls;
private String ts;
private String https_ts;
private String ws_ts;
private String wss_ts;
private String rtmp;
private String rtmps;
private String rtsp;
private String rtsps;
private String rtc;
private String mediaServerId;
private JSONArray tracks;
public static class TransactionInfo{
@ -165,4 +176,92 @@ public class StreamInfo {
public void setTransactionInfo(TransactionInfo transactionInfo) {
this.transactionInfo = transactionInfo;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
public String getHttps_flv() {
return https_flv;
}
public void setHttps_flv(String https_flv) {
this.https_flv = https_flv;
}
public String getWss_flv() {
return wss_flv;
}
public void setWss_flv(String wss_flv) {
this.wss_flv = wss_flv;
}
public String getWss_fmp4() {
return wss_fmp4;
}
public void setWss_fmp4(String wss_fmp4) {
this.wss_fmp4 = wss_fmp4;
}
public String getWss_hls() {
return wss_hls;
}
public void setWss_hls(String wss_hls) {
this.wss_hls = wss_hls;
}
public String getWss_ts() {
return wss_ts;
}
public void setWss_ts(String wss_ts) {
this.wss_ts = wss_ts;
}
public String getRtmps() {
return rtmps;
}
public void setRtmps(String rtmps) {
this.rtmps = rtmps;
}
public String getRtsps() {
return rtsps;
}
public void setRtsps(String rtsps) {
this.rtsps = rtsps;
}
public String getHttps_hls() {
return https_hls;
}
public void setHttps_hls(String https_hls) {
this.https_hls = https_hls;
}
public String getHttps_fmp4() {
return https_fmp4;
}
public void setHttps_fmp4(String https_fmp4) {
this.https_fmp4 = https_fmp4;
}
public String getHttps_ts() {
return https_ts;
}
public void setHttps_ts(String https_ts) {
this.https_ts = https_ts;
}
}

39
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java

@ -1,40 +1,39 @@
package com.genersoft.iot.vmp.common;
/**
* @Description: 定义常量
* @author: swwheihei
* @date: 2019年5月30日 下午3:04:04
*
* 定义常量
*/
public class VideoManagerConstants {
public static final String MEDIA_SERVER_PREFIX = "VMP_media_server";
public static final String WVP_SERVER_PREFIX = "VMP_wvp_server";
public static final String MEDIA_STREAM_PREFIX = "VMP_media_stream";
public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
public static final String DEVICE_PREFIX = "VMP_device_";
public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS";
public static final String CACHEKEY_PREFIX = "VMP_channel_";
public static final String MEDIA_STREAM_PREFIX = "VMP_MEDIA_STREAM";
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
public static final String DEVICE_PREFIX = "VMP_DEVICE_";
public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
public static final String PLAYER_PREFIX = "VMP_player_";
public static final String KEEPLIVEKEY_PREFIX = "VMP_keeplive_";
public static final String PLAY_BLACK_PREFIX = "VMP_playback_";
public static final String PLAYER_PREFIX = "VMP_PLAYER_";
public static final String PLATFORM_PREFIX = "VMP_platform";
public static final String PLAY_BLACK_PREFIX = "VMP_PLAYBACK_";
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_platform_keeplive_";
public static final String PLATFORM_KEEPLIVEKEY_PREFIX = "VMP_PLATFORM_KEEPLIVE_";
public static final String PLATFORM_CATCH_PREFIX = "VMP_platform_catch_";
public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
public static final String PLATFORM_REGISTER_PREFIX = "VMP_platform_register_";
public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_platform_register_info_";
public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_platform_send_rtp_info_";
public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
public static final String Pattern_Topic = "VMP_keeplive_platform_";
public static final String Pattern_Topic = "VMP_KEEPLIVE_PLATFORM_";
public static final String EVENT_ONLINE_REGISTER = "1";
@ -45,4 +44,8 @@ public class VideoManagerConstants {
public static final String EVENT_OUTLINE_UNREGISTER = "1";
public static final String EVENT_OUTLINE_TIMEOUT = "2";
public static final String MEDIA_SSRC_USED_PREFIX = "VMP_media_used_ssrc_";
public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_media_transaction_";
}

28
src/main/java/com/genersoft/iot/vmp/common/reponse/ErrorResponseData.java

@ -0,0 +1,28 @@
package com.genersoft.iot.vmp.common.reponse;
public class ErrorResponseData extends ResponseData{
/**
* 异常的具体类名称
*/
private String exceptionClazz;
public String getExceptionClazz() {
return exceptionClazz;
}
public void setExceptionClazz(String exceptionClazz) {
this.exceptionClazz = exceptionClazz;
}
ErrorResponseData(String message) {
super(false, DEFAULT_ERROR_CODE, message, null);
}
public ErrorResponseData(Integer code, String message) {
super(false, code, message, null);
}
ErrorResponseData(Integer code, String message, Object object) {
super(false, code, message, object);
}
}

98
src/main/java/com/genersoft/iot/vmp/common/reponse/ResponseData.java

@ -0,0 +1,98 @@
package com.genersoft.iot.vmp.common.reponse;
public class ResponseData {
public static final String DEFAULT_SUCCESS_MESSAGE = "请求成功";
public static final String DEFAULT_ERROR_MESSAGE = "网络异常";
public static final Integer DEFAULT_SUCCESS_CODE = 200;
public static final Integer DEFAULT_ERROR_CODE = 500;
/**
* 请求是否成功
*/
private Boolean success;
/**
* 响应状态码
*/
private Integer code;
/**
* 响应信息
*/
private String message;
/**
* 响应对象
*/
private Object data;
public ResponseData() {
}
public ResponseData(Boolean success, Integer code, String message, Object data) {
this.success = success;
this.code = code;
this.message = message;
this.data = data;
}
public static SuccessResponseData success() {
return new SuccessResponseData();
}
public static SuccessResponseData success(Object object) {
return new SuccessResponseData(object);
}
public static SuccessResponseData success(Integer code, String message, Object object) {
return new SuccessResponseData(code, message, object);
}
public static ErrorResponseData error(String message) {
return new ErrorResponseData(message);
}
public static ErrorResponseData error(Integer code, String message) {
return new ErrorResponseData(code, message);
}
public static ErrorResponseData error(Integer code, String message, Object object) {
return new ErrorResponseData(code, message, object);
}
public Boolean getSuccess() {
return success;
}
public void setSuccess(Boolean success) {
this.success = success;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}

15
src/main/java/com/genersoft/iot/vmp/common/reponse/SuccessResponseData.java

@ -0,0 +1,15 @@
package com.genersoft.iot.vmp.common.reponse;
public class SuccessResponseData extends ResponseData {
public SuccessResponseData() {
super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, null);
}
public SuccessResponseData(Object object) {
super(true, DEFAULT_SUCCESS_CODE, DEFAULT_SUCCESS_MESSAGE, object);
}
public SuccessResponseData(Integer code, String message, Object object) {
super(true, code, message, object);
}
}

96
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java

@ -0,0 +1,96 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.common.ApiSaveConstant;
import com.genersoft.iot.vmp.service.ILogService;
import com.genersoft.iot.vmp.storager.dao.dto.LogDto;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.text.SimpleDateFormat;
@WebFilter(filterName = "ApiAccessFilter", urlPatterns = "/api/*", asyncSupported = true)
public class ApiAccessFilter extends OncePerRequestFilter {
private final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@Autowired
private UserSetup userSetup;
@Autowired
private ILogService logService;
@Override
protected void doFilterInternal(HttpServletRequest servletRequest, HttpServletResponse servletResponse, FilterChain filterChain) throws ServletException, IOException {
long start = System.currentTimeMillis(); // 请求进入时间
String uriName = ApiSaveConstant.getVal(servletRequest.getRequestURI());
filterChain.doFilter(servletRequest, servletResponse);
if (uriName != null && userSetup.getLogInDatebase()) {
LogDto logDto = new LogDto();
logDto.setName(uriName);
logDto.setAddress(servletRequest.getRemoteAddr());
logDto.setResult(HttpStatus.valueOf(servletResponse.getStatus()).toString());
logDto.setTiming(System.currentTimeMillis() - start);
logDto.setType(servletRequest.getMethod());
logDto.setUri(servletRequest.getRequestURI());
logDto.setCreateTime(format.format(System.currentTimeMillis()));
logService.add(logDto);
}
}
/**
* 获取IP地址
*
* @param request 请求
* @return request发起客户端的IP地址
*/
private String getIP(HttpServletRequest request) {
if (request == null) {
return "0.0.0.0";
}
String Xip = request.getHeader("X-Real-IP");
String XFor = request.getHeader("X-Forwarded-For");
String UNKNOWN_IP = "unknown";
if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
//多次反向代理后会有多个ip值,第一个ip才是真实ip
int index = XFor.indexOf(",");
if (index != -1) {
return XFor.substring(0, index);
} else {
return XFor;
}
}
XFor = Xip;
if (StringUtils.isNotEmpty(XFor) && !UNKNOWN_IP.equalsIgnoreCase(XFor)) {
return XFor;
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("WL-Proxy-Client-IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_CLIENT_IP");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (StringUtils.isBlank(XFor) || UNKNOWN_IP.equalsIgnoreCase(XFor)) {
XFor = request.getRemoteAddr();
}
return XFor;
}
}

42
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java

@ -0,0 +1,42 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* 动态定时任务
*/
@Component
public class DynamicTask {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
private Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
public String startCron(String key, Runnable task, String corn) {
stopCron(key);
ScheduledFuture future = threadPoolTaskScheduler.schedule(task, new CronTrigger(corn));
futureMap.put(key, future);
return "startCron";
}
public void stopCron(String key) {
if (futureMap.get(key) != null && !futureMap.get(key).isCancelled()) {
futureMap.get(key).cancel(true);
}
}
}

222
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java

@ -1,72 +1,86 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import java.text.SimpleDateFormat;
import java.util.Date;
@Configuration("mediaConfig")
public class MediaConfig {
public class MediaConfig{
@Value("${media.id:}")
private String id;
@Value("${media.ip}")
private String ip;
@Value("${media.hookIp:${sip.ip}}")
@Value("${media.hook-ip:${sip.ip}}")
private String hookIp;
@Value("${sip.ip}")
private String sipIp;
@Value("${media.sdpIp:${media.ip}}")
@Value("${sip.domain}")
private String sipDomain;
@Value("${media.sdp-ip:${media.ip}}")
private String sdpIp;
@Value("${media.streamIp:${media.ip}}")
@Value("${media.stream-ip:${media.ip}}")
private String streamIp;
@Value("${media.httpPort}")
@Value("${media.http-port}")
private Integer httpPort;
@Value("${media.httpSSlPort:}")
private Integer httpSSlPort;
@Value("${media.http-ssl-port:0}")
private Integer httpSSlPort = 0;
@Value("${media.rtmpPort:}")
private Integer rtmpPort;
@Value("${media.rtmp-port:0}")
private Integer rtmpPort = 0;
@Value("${media.rtmpSSlPort:}")
private Integer rtmpSSlPort;
@Value("${media.rtmp-ssl-port:0}")
private Integer rtmpSSlPort = 0;
@Value("${media.rtpProxyPort:}")
private Integer rtpProxyPort;
@Value("${media.rtp-proxy-port:0}")
private Integer rtpProxyPort = 0;
@Value("${media.rtspPort:}")
private Integer rtspPort;
@Value("${media.rtsp-port:0}")
private Integer rtspPort = 0;
@Value("${media.rtspSSLPort:}")
private Integer rtspSSLPort;
@Value("${media.rtsp-ssl-port:0}")
private Integer rtspSSLPort = 0;
@Value("${media.autoConfig:true}")
private boolean autoConfig;
@Value("${media.auto-config:true}")
private boolean autoConfig = true;
@Value("${media.secret}")
private String secret;
@Value("${media.streamNoneReaderDelayMS:18000}")
private String streamNoneReaderDelayMS;
@Value("${media.stream-none-reader-delay-ms:18000}")
private String streamNoneReaderDelayMS = "18000";
@Value("${media.rtp.enable}")
private boolean rtpEnable;
@Value("${media.rtp.portRange}")
@Value("${media.rtp.port-range}")
private String rtpPortRange;
@Value("${media.recordAssistPort}")
private Integer recordAssistPort;
public String getIp() {
return ip;
@Value("${media.rtp.send-port-range}")
private String sendRtpPortRange;
@Value("${media.record-assist-port:0}")
private Integer recordAssistPort = 0;
public String getId() {
return id;
}
public void setIp(String ip) {
this.ip = ip;
public String getIp() {
return ip;
}
public String getHookIp() {
@ -78,135 +92,123 @@ public class MediaConfig {
}
public void setHookIp(String hookIp) {
this.hookIp = hookIp;
}
public String getSdpIp() {
if (StringUtils.isEmpty(sdpIp)){
return ip;
public String getSipIp() {
if (sipIp == null) {
return this.ip;
}else {
return sdpIp;
}
}
public void setSdpIp(String sdpIp) {
this.sdpIp = sdpIp;
}
public String getStreamIp() {
if (StringUtils.isEmpty(streamIp)){
return ip;
}else {
return streamIp;
return sipIp;
}
}
public void setStreamIp(String streamIp) {
this.streamIp = streamIp;
}
public Integer getHttpPort() {
public int getHttpPort() {
return httpPort;
}
public void setHttpPort(Integer httpPort) {
this.httpPort = httpPort;
}
public Integer getHttpSSlPort() {
public int getHttpSSlPort() {
return httpSSlPort;
}
public void setHttpSSlPort(Integer httpSSlPort) {
this.httpSSlPort = httpSSlPort;
}
public Integer getRtmpPort() {
public int getRtmpPort() {
return rtmpPort;
}
public void setRtmpPort(Integer rtmpPort) {
this.rtmpPort = rtmpPort;
}
public Integer getRtmpSSlPort() {
public int getRtmpSSlPort() {
return rtmpSSlPort;
}
public void setRtmpSSlPort(Integer rtmpSSlPort) {
this.rtmpSSlPort = rtmpSSlPort;
}
public Integer getRtpProxyPort() {
return rtpProxyPort;
}
public int getRtpProxyPort() {
if (rtpProxyPort == null) {
return 0;
}else {
return rtpProxyPort;
}
public void setRtpProxyPort(Integer rtpProxyPort) {
this.rtpProxyPort = rtpProxyPort;
}
public Integer getRtspPort() {
public int getRtspPort() {
return rtspPort;
}
public void setRtspPort(Integer rtspPort) {
this.rtspPort = rtspPort;
}
public Integer getRtspSSLPort() {
public int getRtspSSLPort() {
return rtspSSLPort;
}
public void setRtspSSLPort(Integer rtspSSLPort) {
this.rtspSSLPort = rtspSSLPort;
}
public boolean isAutoConfig() {
return autoConfig;
}
public void setAutoConfig(boolean autoConfig) {
this.autoConfig = autoConfig;
}
public String getSecret() {
return secret;
}
public void setSecret(String secret) {
this.secret = secret;
}
public String getStreamNoneReaderDelayMS() {
return streamNoneReaderDelayMS;
}
public void setStreamNoneReaderDelayMS(String streamNoneReaderDelayMS) {
this.streamNoneReaderDelayMS = streamNoneReaderDelayMS;
}
public boolean isRtpEnable() {
return rtpEnable;
}
public void setRtpEnable(boolean rtpEnable) {
this.rtpEnable = rtpEnable;
}
public String getRtpPortRange() {
return rtpPortRange;
}
public int getRecordAssistPort() {
return recordAssistPort;
}
public void setRtpPortRange(String rtpPortRange) {
this.rtpPortRange = rtpPortRange;
public String getSdpIp() {
if (StringUtils.isEmpty(sdpIp)){
return ip;
}else {
return sdpIp;
}
}
public Integer getRecordAssistPort() {
return recordAssistPort;
public String getStreamIp() {
if (StringUtils.isEmpty(streamIp)){
return ip;
}else {
return streamIp;
}
}
public void setRecordAssistPort(Integer recordAssistPort) {
this.recordAssistPort = recordAssistPort;
public String getSipDomain() {
return sipDomain;
}
public String getSendRtpPortRange() {
return sendRtpPortRange;
}
public MediaServerItem getMediaSerItem(){
MediaServerItem mediaServerItem = new MediaServerItem();
mediaServerItem.setId(id);
mediaServerItem.setIp(ip);
mediaServerItem.setDefaultServer(true);
mediaServerItem.setHookIp(getHookIp());
mediaServerItem.setSdpIp(getSdpIp());
mediaServerItem.setStreamIp(getStreamIp());
mediaServerItem.setHttpPort(httpPort);
mediaServerItem.setHttpSSlPort(httpSSlPort);
mediaServerItem.setRtmpPort(rtmpPort);
mediaServerItem.setRtmpSSlPort(rtmpSSlPort);
mediaServerItem.setRtpProxyPort(getRtpProxyPort());
mediaServerItem.setRtspPort(rtspPort);
mediaServerItem.setRtspSSLPort(rtspSSLPort);
mediaServerItem.setAutoConfig(autoConfig);
mediaServerItem.setSecret(secret);
mediaServerItem.setStreamNoneReaderDelayMS(streamNoneReaderDelayMS);
mediaServerItem.setRtpEnable(rtpEnable);
mediaServerItem.setRtpPortRange(rtpPortRange);
mediaServerItem.setSendRtpPortRange(sendRtpPortRange);
mediaServerItem.setRecordAssistPort(recordAssistPort);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
mediaServerItem.setCreateTime(format.format(System.currentTimeMillis()));
mediaServerItem.setUpdateTime(format.format(System.currentTimeMillis()));
return mediaServerItem;
}
}

191
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java

@ -1,12 +1,16 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import org.apache.catalina.connector.ClientAbortException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.catalina.connector.ClientAbortException;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -24,13 +28,16 @@ public class ProxyServletConfig {
private final static Logger logger = LoggerFactory.getLogger(ProxyServletConfig.class);
@Autowired
private MediaConfig mediaConfig;
private IMediaServerService mediaServerService;
@Value("${server.port}")
private int serverPort;
@Bean
public ServletRegistrationBean zlmServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZLMProxySerlet(),"/zlm/*");
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ZlmProxyServlet(),"/zlm/*");
servletRegistrationBean.setName("zlm_Proxy");
servletRegistrationBean.addInitParameter("targetUri", String.format("http://%s:%s", mediaConfig.getIp(), mediaConfig.getHttpPort()));
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:6080");
servletRegistrationBean.addUrlMappings();
if (logger.isDebugEnabled()) {
servletRegistrationBean.addInitParameter("log", "true");
@ -38,24 +45,26 @@ public class ProxyServletConfig {
return servletRegistrationBean;
}
class ZLMProxySerlet extends ProxyServlet{
class ZlmProxyServlet extends ProxyServlet{
@Override
protected String rewriteQueryStringFromRequest(HttpServletRequest servletRequest, String queryString) {
String queryStr = super.rewriteQueryStringFromRequest(servletRequest, queryString);
if (!StringUtils.isEmpty(queryStr)) {
queryStr += "&secret=" + mediaConfig.getSecret();
}else {
queryStr = "secret=" + mediaConfig.getSecret();
MediaServerItem mediaInfo = getMediaInfoByUri(servletRequest.getRequestURI());
if (mediaInfo != null) {
if (!StringUtils.isEmpty(queryStr)) {
queryStr += "&secret=" + mediaInfo.getSecret();
}else {
queryStr = "secret=" + mediaInfo.getSecret();
}
}
return queryStr;
}
/**
* 异常处理
*/
@Override
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
//System.out.println(e.getMessage());
try {
super.handleRequestException(proxyRequest, proxyResonse, e);
} catch (ServletException servletException) {
@ -64,7 +73,7 @@ public class ProxyServletConfig {
if (ioException instanceof ConnectException) {
logger.error("zlm 连接失败");
} else if (ioException instanceof ClientAbortException) {
logger.error("用户已中断连接,代理终止");
logger.error("zlm: 用户已中断连接,代理终止");
} else {
logger.error("zlm 代理失败: ", e);
}
@ -72,6 +81,160 @@ public class ProxyServletConfig {
logger.error("zlm 代理失败: ", e);
}
}
/**
* 对于为按照格式请求的可以直接返回404
*/
@Override
protected String getTargetUri(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
String uri = null;
if (mediaInfo != null) {
// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getHttpPort());
}else {
uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已, 其他的也可以
}
return uri;
}
/**
* 动态替换请求目标
*/
@Override
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
HttpHost host;
if (mediaInfo != null) {
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getHttpPort());
}else {
host = new HttpHost("127.0.0.1", serverPort);
}
return host;
}
/**
* 根据uri获取流媒体信息
*/
MediaServerItem getMediaInfoByUri(String uri){
String[] split = uri.split("/");
String mediaServerId = split[2];
return mediaServerService.getOne(mediaServerId);
}
/**
* 去掉url中的标志信息
*/
@Override
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
String url = super.rewriteUrlFromRequest(servletRequest);
if (mediaInfo == null) {
return url;
}
return url.replace(mediaInfo.getId() + "/", "");
}
}
@Bean
public ServletRegistrationBean recordServletRegistrationBean(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new RecordProxySerlet(),"/record_proxy/*");
servletRegistrationBean.setName("record_proxy");
servletRegistrationBean.addInitParameter("targetUri", "http://127.0.0.1:18081");
servletRegistrationBean.addUrlMappings();
if (logger.isDebugEnabled()) {
servletRegistrationBean.addInitParameter("log", "true");
}
return servletRegistrationBean;
}
class RecordProxySerlet extends ProxyServlet{
/**
* 异常处理
*/
@Override
protected void handleRequestException(HttpRequest proxyRequest, HttpResponse proxyResonse, Exception e){
try {
super.handleRequestException(proxyRequest, proxyResonse, e);
} catch (ServletException servletException) {
logger.error("录像服务 代理失败: ", e);
} catch (IOException ioException) {
if (ioException instanceof ConnectException) {
logger.error("录像服务 连接失败");
} else if (ioException instanceof ClientAbortException) {
logger.error("录像服务:用户已中断连接,代理终止");
} else {
logger.error("录像服务 代理失败: ", e);
}
} catch (RuntimeException exception){
logger.error("录像服务 代理失败: ", e);
}
}
/**
* 对于为按照格式请求的可以直接返回404
*/
@Override
protected String getTargetUri(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
String uri = null;
if (mediaInfo != null) {
// String realRequestURI = requestURI.substring(requestURI.indexOf(mediaInfo.getId())+ mediaInfo.getId().length());
uri = String.format("http://%s:%s", mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
}else {
uri = "http://127.0.0.1:" + serverPort +"/index/hook/null"; // 只是一个能返回404的请求而已, 其他的也可以
}
return uri;
}
/**
* 动态替换请求目标
*/
@Override
protected HttpHost getTargetHost(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
HttpHost host;
if (mediaInfo != null) {
host = new HttpHost(mediaInfo.getIp(), mediaInfo.getRecordAssistPort());
}else {
host = new HttpHost("127.0.0.1", serverPort);
}
return host;
}
/**
* 根据uri获取流媒体信息
*/
MediaServerItem getMediaInfoByUri(String uri){
String[] split = uri.split("/");
String mediaServerId = split[2];
return mediaServerService.getOne(mediaServerId);
}
/**
* 去掉url中的标志信息
*/
@Override
protected String rewriteUrlFromRequest(HttpServletRequest servletRequest) {
String requestURI = servletRequest.getRequestURI();
MediaServerItem mediaInfo = getMediaInfoByUri(requestURI);
String url = super.rewriteUrlFromRequest(servletRequest);
if (mediaInfo == null) {
return url;
}
return url.replace(mediaInfo.getId() + "/", "");
}
}
}

90
src/main/java/com/genersoft/iot/vmp/conf/RedisConfig.java

@ -1,5 +1,7 @@
package com.genersoft.iot.vmp.conf;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -10,44 +12,70 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.alibaba.fastjson.parser.ParserConfig;
import com.genersoft.iot.vmp.utils.redis.FastJsonRedisSerializer;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/**
* @Description:Redis中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
* @author: swwheihei
* @date: 2019年5月30日 上午10:58:25
*
* 中间件配置类使用spring-data-redis集成自动从application.yml中加载redis配置
*/
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean("redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 使用fastjson进行序列化处理,提高解析效率
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
// 使用fastjson时需设置此项,否则会报异常not support type
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
return template;
}
/**
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器只需要把消息监听器和相应的消息订阅处理器绑定该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*
* @param connectionFactory
* @return
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private int timeout;
@Value("${spring.redis.poolMaxTotal:1000}")
private int poolMaxTotal;
@Value("${spring.redis.poolMaxIdle:500}")
private int poolMaxIdle;
@Value("${spring.redis.poolMaxWait:5}")
private int poolMaxWait;
@Bean
public JedisPool jedisPool() {
if (StringUtils.isBlank(password)) {
password = null;
}
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(poolMaxIdle);
poolConfig.setMaxTotal(poolMaxTotal);
// 秒转毫秒
poolConfig.setMaxWaitMillis(poolMaxWait * 1000L);
JedisPool jp = new JedisPool(poolConfig, host, port, timeout * 1000, password, database);
return jp;
}
@Bean("redisTemplate")
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
// 使用fastjson进行序列化处理,提高解析效率
FastJsonRedisSerializer<Object> serializer = new FastJsonRedisSerializer<Object>(Object.class);
// value值的序列化采用fastJsonRedisSerializer
template.setValueSerializer(serializer);
template.setHashValueSerializer(serializer);
// key的序列化采用StringRedisSerializer
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setConnectionFactory(redisConnectionFactory);
// 使用fastjson时需设置此项,否则会报异常not support type
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
return template;
}
/**
* redis消息监听器容器 可以添加多个监听不同话题的redis监听器只需要把消息监听器和相应的消息订阅处理器绑定该消息监听器
* 通过反射技术调用消息订阅处理器的相关方法进行一些业务处理
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
return container;

96
src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java

@ -1,72 +1,100 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Configuration("sipConfig")
@Component
@ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true)
public class SipConfig {
@Value("${sip.ip}")
private String sipIp;
private String ip;
/**
* 默认使用sip.ip
* 默认使用 0.0.0.0
*/
@Value("${sip.monitorIp:0.0.0.0}")
private String monitorIp;
private String monitorIp = "0.0.0.0";
@Value("${sip.port}")
private Integer sipPort;
private Integer port;
@Value("${sip.domain}")
private String sipDomain;
private String domain;
@Value("${sip.id}")
private String sipId;
private String id;
@Value("${sip.password}")
private String sipPassword;
private String password;
@Value("${sip.ptz.speed:50}")
Integer speed;
Integer ptzSpeed = 50;
@Value("${sip.keepaliveTimeOut:180}")
Integer keepaliveTimeOut;
Integer keepaliveTimeOut = 255;
@Value("${sip.registerTimeInterval:60}")
Integer registerTimeInterval;
Integer registerTimeInterval = 60;
public void setIp(String ip) {
this.ip = ip;
}
public void setMonitorIp(String monitorIp) {
this.monitorIp = monitorIp;
}
public void setPort(Integer port) {
this.port = port;
}
public void setDomain(String domain) {
this.domain = domain;
}
public void setId(String id) {
this.id = id;
}
public void setPassword(String password) {
this.password = password;
}
public void setPtzSpeed(Integer ptzSpeed) {
this.ptzSpeed = ptzSpeed;
}
public void setKeepaliveTimeOut(Integer keepaliveTimeOut) {
this.keepaliveTimeOut = keepaliveTimeOut;
}
public void setRegisterTimeInterval(Integer registerTimeInterval) {
this.registerTimeInterval = registerTimeInterval;
}
public String getMonitorIp() {
return monitorIp;
}
public String getSipIp() {
return sipIp;
public String getIp() {
return ip;
}
public Integer getSipPort() {
return sipPort;
public Integer getPort() {
return port;
}
public String getSipDomain() {
return sipDomain;
public String getDomain() {
return domain;
}
public String getSipId() {
return sipId;
public String getId() {
return id;
}
public String getSipPassword() {
return sipPassword;
public String getPassword() {
return password;
}
public Integer getSpeed() {
return speed;
public Integer getPtzSpeed() {
return ptzSpeed;
}
public Integer getKeepaliveTimeOut() {

10
src/main/java/com/genersoft/iot/vmp/conf/SipDeviceRunner.java

@ -7,6 +7,7 @@ import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 系统启动时控制设备离线
@ -23,9 +24,14 @@ public class SipDeviceRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
// 读取redis没有心跳信息的则设置为离线,等收到下次心跳设置为在线
// 设置所有设备离线
storager.outlineForAll();
// 设置所有设备离线
redisCatchStorage.outlineForAll();
List<String> onlineForAll = redisCatchStorage.getOnlineForAll();
for (String deviceId : onlineForAll) {
storager.online(deviceId);
}
// TODO 查询在线设备那些开启了订阅,为设备开启定时的目录订阅
}
}

6
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java

@ -29,10 +29,6 @@ public class SipPlatformRunner implements CommandLineRunner {
@Autowired
private EventPublisher publisher;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Override
public void run(String... args) throws Exception {
// 设置所有平台离线
@ -42,7 +38,7 @@ public class SipPlatformRunner implements CommandLineRunner {
redisCatchStorage.cleanPlatformRegisterInfos();
// 停止所有推流
// zlmrtpServerFactory.closeAllSendRtpStream();
// zlmrtpServerFactory.closeAllSendRtpStream();
List<ParentPlatform> parentPlatforms = storager.queryEnableParentPlatformList(true);

52
src/main/java/com/genersoft/iot/vmp/conf/Swagger3Config.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
@ -13,49 +14,70 @@ import springfox.documentation.spring.web.plugins.Docket;
@Configuration
public class Swagger3Config {
@Value("${swagger-ui.enabled}")
private boolean enable;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("全部")
.groupName("1. 全部")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestGBApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("国标")
.groupName("2. 国标28181")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.gb28181"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestONVIFApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("3. ONVIF")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.onvif"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestStreamProxyApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("拉流转发")
.groupName("4. 拉流转发")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.streamProxy"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createRestStreamPushApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("推流管理")
.groupName("5. 推流管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.streamPush"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
@ -63,30 +85,32 @@ public class Swagger3Config {
public Docket createServerApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("服务管理")
.groupName("6. 服务管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.server"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
@Bean
public Docket createUserApi() {
return new Docket(DocumentationType.OAS_30)
.apiInfo(apiInfo())
.groupName("用户管理")
.groupName("7. 用户管理")
.select()
.apis(RequestHandlerSelectors.basePackage("com.genersoft.iot.vmp.vmanager.user"))
.paths(PathSelectors.any())
.build()
.pathMapping("/");
.pathMapping("/")
.enable(enable);
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("WVP-PRO 接口文档")
.description("更多请咨询服务开发者(18010473990@@163.com)。")
.contact(new Contact("panlinlin", "http://www.ruiyeclub.cn", "ruiyeclub@foxmail.com"))
.description("更多请咨询服务开发者(https://github.com/648540858/wvp-GB28181-pro)。")
.contact(new Contact("648540858", "648540858", "648540858@qq.com"))
.version("2.0")
.build();
}

96
src/main/java/com/genersoft/iot/vmp/conf/UserSetup.java

@ -1,60 +1,106 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Configuration("userSetup")
import java.util.ArrayList;
import java.util.List;
@Component
@ConfigurationProperties(prefix = "user-settings", ignoreInvalidFields = true)
public class UserSetup {
@Value("${userSettings.savePositionHistory:false}")
boolean savePositionHistory;
@Value("${userSettings.autoApplyPlay}")
private boolean autoApplyPlay;
private Boolean savePositionHistory = Boolean.FALSE;
private Boolean autoApplyPlay = Boolean.FALSE;
private Boolean seniorSdp = Boolean.FALSE;
private Long playTimeout = 18000L;
@Value("${userSettings.seniorSdp:false}")
private boolean seniorSdp;
private Boolean waitTrack = Boolean.FALSE;
@Value("${userSettings.playTimeout:18000}")
private long playTimeout;
private Boolean interfaceAuthentication = Boolean.TRUE;
@Value("${userSettings.waitTrack:false}")
private boolean waitTrack;
private Boolean recordPushLive = Boolean.FALSE;
@Value("${userSettings.interfaceAuthentication}")
private boolean interfaceAuthentication;
private Boolean logInDatebase = Boolean.TRUE;
@Value("${userSettings.recordPushLive}")
private boolean recordPushLive;
private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
public boolean getSavePositionHistory() {
public Boolean getSavePositionHistory() {
return savePositionHistory;
}
public boolean isSavePositionHistory() {
public Boolean isSavePositionHistory() {
return savePositionHistory;
}
public boolean isAutoApplyPlay() {
public Boolean isAutoApplyPlay() {
return autoApplyPlay;
}
public boolean isSeniorSdp() {
public Boolean isSeniorSdp() {
return seniorSdp;
}
public long getPlayTimeout() {
public Long getPlayTimeout() {
return playTimeout;
}
public boolean isWaitTrack() {
public Boolean isWaitTrack() {
return waitTrack;
}
public boolean isInterfaceAuthentication() {
public Boolean isInterfaceAuthentication() {
return interfaceAuthentication;
}
public boolean isRecordPushLive() {
public Boolean isRecordPushLive() {
return recordPushLive;
}
public List<String> getInterfaceAuthenticationExcludes() {
return interfaceAuthenticationExcludes;
}
public void setSavePositionHistory(Boolean savePositionHistory) {
this.savePositionHistory = savePositionHistory;
}
public void setAutoApplyPlay(Boolean autoApplyPlay) {
this.autoApplyPlay = autoApplyPlay;
}
public void setSeniorSdp(Boolean seniorSdp) {
this.seniorSdp = seniorSdp;
}
public void setPlayTimeout(Long playTimeout) {
this.playTimeout = playTimeout;
}
public void setWaitTrack(Boolean waitTrack) {
this.waitTrack = waitTrack;
}
public void setInterfaceAuthentication(boolean interfaceAuthentication) {
this.interfaceAuthentication = interfaceAuthentication;
}
public void setRecordPushLive(Boolean recordPushLive) {
this.recordPushLive = recordPushLive;
}
public void setInterfaceAuthenticationExcludes(List<String> interfaceAuthenticationExcludes) {
this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes;
}
public Boolean getLogInDatebase() {
return logInDatebase;
}
public void setLogInDatebase(Boolean logInDatebase) {
this.logInDatebase = logInDatebase;
}
}

25
src/main/java/com/genersoft/iot/vmp/conf/VManagerConfig.java

@ -1,25 +0,0 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* @Description: 获取数据库配置
* @author: swwheihei
* @date: 2020年5月6日 下午2:46:00
*/
@Configuration("vmConfig")
public class VManagerConfig {
@Value("${spring.application.database:redis}")
private String database;
public String getDatabase() {
return database;
}
public void setDatabase(String database) {
this.database = database;
}
}

24
src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java

@ -0,0 +1,24 @@
package com.genersoft.iot.vmp.conf;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class WVPTimerTask {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private SipConfig sipConfig;
@Autowired
private MediaConfig mediaConfig;
// @Scheduled(cron="0/2 * * * * ? ") //每3秒执行一次
// public void execute(){
//// redisCatchStorage.updateWVPInfo();
// }
}

28
src/main/java/com/genersoft/iot/vmp/conf/WebConfig.java

@ -0,0 +1,28 @@
package com.genersoft.iot.vmp.conf;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
// 设置允许跨域请求
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*") // 允许所有域
.allowedMethods("*") // 允许任何方法(post、get等)
.allowedHeaders("*") // 允许任何请求头
.allowCredentials(true) // 允许证书、cookie
.exposedHeaders(HttpHeaders.SET_COOKIE)
.maxAge(3600L); // maxAge(3600)表明在3600秒内,不需要再发送预检验请求,可以缓存该结果
}
};
}
}

5
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java

@ -28,8 +28,11 @@ public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoi
response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
response.setHeader("Content-type", "application/json;charset=UTF-8");
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg", e.getMessage());
jsonObject.put("code", "-1");
jsonObject.put("msg", "请登录后重新请求");
if (request.getRequestURI().contains("api/user/login")){
jsonObject.put("msg", e.getMessage());
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
try {
response.getWriter().print(jsonObject.toJSONString());

2
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java

@ -48,7 +48,7 @@ public class SecurityUtils {
Authentication authentication = getAuthentication();
if(authentication!=null){
Object principal = authentication.getPrincipal();
if(principal!=null){
if(principal!=null && !"anonymousUser".equals(principal)){
LoginUser user = (LoginUser) authentication.getPrincipal();
return user;
}

15
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java

@ -1,6 +1,8 @@
package com.genersoft.iot.vmp.conf.security;
import com.genersoft.iot.vmp.conf.UserSetup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -14,6 +16,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.List;
/**
* 配置Spring Security
*/
@ -22,6 +26,8 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final static Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
@Autowired
private UserSetup userSetup;
@ -85,6 +91,15 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
.antMatchers("/swagger-resources/**")
.antMatchers("/v3/api-docs/**")
.antMatchers("/js/**");
List<String> interfaceAuthenticationExcludes = userSetup.getInterfaceAuthenticationExcludes();
for (String interfaceAuthenticationExclude : interfaceAuthenticationExcludes) {
if (interfaceAuthenticationExclude.split("/").length < 4 ) {
logger.warn("{}不满足两级目录,已忽略", interfaceAuthenticationExclude);
}else {
web.ignoring().antMatchers(interfaceAuthenticationExclude);
}
}
}
}

7
src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf.security.dto;
import com.genersoft.iot.vmp.storager.dao.dto.Role;
import com.genersoft.iot.vmp.storager.dao.dto.User;
import org.springframework.security.core.CredentialsContainer;
import org.springframework.security.core.GrantedAuthority;
@ -92,4 +93,10 @@ public class LoginUser implements UserDetails, CredentialsContainer {
public int getId() {
return user.getId();
}
public Role getRole() {
return user.getRole();
}
}

215
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java

@ -1,17 +1,10 @@
package com.genersoft.iot.vmp.gb28181;
import java.text.ParseException;
import java.util.Properties;
import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.sip.*;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -19,14 +12,15 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorFactory;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
import gov.nist.javax.sip.SipStackImpl;
import javax.sip.*;
import java.util.Properties;
import java.util.TooManyListenersException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Component
public class SipLayer implements SipListener {
public class SipLayer{
private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
@ -34,12 +28,12 @@ public class SipLayer implements SipListener {
private SipConfig sipConfig;
@Autowired
private SIPProcessorFactory processorFactory;
private SIPProcessorObserver sipProcessorObserver;
@Autowired
private SipSubscribe sipSubscribe;
private SipStack sipStack;
private SipStackImpl sipStack;
private SipFactory sipFactory;
@ -48,19 +42,16 @@ public class SipLayer implements SipListener {
*/
private ThreadPoolExecutor processThreadPool;
@Bean("initSipServer")
private ThreadPoolExecutor initSipServer() {
public SipLayer() {
int processThreadNum = Runtime.getRuntime().availableProcessors() * 10;
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<Runnable>(10000);
LinkedBlockingQueue<Runnable> processQueue = new LinkedBlockingQueue<>(10000);
processThreadPool = new ThreadPoolExecutor(processThreadNum,processThreadNum,
0L,TimeUnit.MILLISECONDS,processQueue,
new ThreadPoolExecutor.CallerRunsPolicy());
return processThreadPool;
}
@Bean("sipFactory")
@DependsOn("initSipServer")
private SipFactory createSipFactory() {
sipFactory = SipFactory.getInstance();
sipFactory.setPathName("gov.nist");
@ -68,7 +59,7 @@ public class SipLayer implements SipListener {
}
@Bean("sipStack")
@DependsOn({"initSipServer", "sipFactory"})
@DependsOn({"sipFactory"})
private SipStack createSipStack() throws PeerUnavailableException {
Properties properties = new Properties();
properties.setProperty("javax.sip.STACK_NAME", "GB28181_SIP");
@ -86,150 +77,50 @@ public class SipLayer implements SipListener {
return sipStack;
}
@Bean("tcpSipProvider")
@Bean(name = "tcpSipProvider")
@DependsOn("sipStack")
private SipProvider startTcpListener() {
private SipProviderImpl startTcpListener() {
ListeningPoint tcpListeningPoint = null;
SipProvider tcpSipProvider = null;
SipProviderImpl tcpSipProvider = null;
try {
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "TCP");
tcpSipProvider = sipStack.createSipProvider(tcpListeningPoint);
tcpSipProvider.addSipListener(this);
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getSipPort() + "}");
} catch (TransportNotSupportedException | InvalidArgumentException | TooManyListenersException | ObjectInUseException e) {
logger.error(String.format("创建SIP服务失败: %s", e.getMessage()));
tcpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "TCP");
tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
tcpSipProvider.addSipListener(sipProcessorObserver);
logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}");
} catch (TransportNotSupportedException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
logger.error("无法使用 [ {}:{} ]作为SIP[ TCP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
, sipConfig.getMonitorIp(), sipConfig.getPort());
} catch (TooManyListenersException e) {
e.printStackTrace();
} catch (ObjectInUseException e) {
e.printStackTrace();
}
return tcpSipProvider;
}
@Bean("udpSipProvider")
@Bean(name = "udpSipProvider")
@DependsOn("sipStack")
private SipProvider startUdpListener() throws Exception {
ListeningPoint udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getSipPort(), "UDP");
SipProvider udpSipProvider = sipStack.createSipProvider(udpListeningPoint);
udpSipProvider.addSipListener(this);
logger.info("Sip Server UDP 启动成功 port {" + sipConfig.getSipPort() + "}");
return udpSipProvider;
}
/**
* SIP服务端接收消息的方法 Content 里面是GBK编码 This method is called by the SIP stack when a
* new request arrives.
*/
@Override
public void processRequest(RequestEvent evt) {
// logger.debug(evt.getRequest().toString());
// 由于jainsip是单线程程序,为提高性能并发处理
processThreadPool.execute(() -> {
if (processorFactory != null) {
processorFactory.createRequestProcessor(evt).process();
}
});
}
@Override
public void processResponse(ResponseEvent evt) {
Response response = evt.getResponse();
// logger.debug(evt.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
try {
processor.process(evt, this, sipConfig);
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应,如101、180等
} else {
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
subscribe.response(evt);
}
}
}
private SipProviderImpl startUdpListener() {
ListeningPoint udpListeningPoint = null;
SipProviderImpl udpSipProvider = null;
try {
udpListeningPoint = sipStack.createListeningPoint(sipConfig.getMonitorIp(), sipConfig.getPort(), "UDP");
udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
udpSipProvider.addSipListener(sipProcessorObserver);
} catch (TransportNotSupportedException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
logger.error("无法使用 [ {}:{} ]作为SIP[ UDP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
, sipConfig.getMonitorIp(), sipConfig.getPort());
} catch (TooManyListenersException e) {
e.printStackTrace();
} catch (ObjectInUseException e) {
e.printStackTrace();
}
}
/**
* <p>
* Title: processTimeout
* </p>
* <p>
* Description:
* </p>
*
* @param timeoutEvent
*/
@Override
public void processTimeout(TimeoutEvent timeoutEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processIOException
* </p>
* <p>
* Description:
* </p>
*
* @param exceptionEvent
*/
@Override
public void processIOException(IOExceptionEvent exceptionEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processTransactionTerminated
* </p>
* <p>
* Description:
* </p>
*
* @param transactionTerminatedEvent
*/
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
// TODO Auto-generated method stub
}
/**
* <p>
* Title: processDialogTerminated
* </p>
* <p>
* Description:
* </p>
*
* @param dialogTerminatedEvent
*/
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
// TODO Auto-generated method stub
logger.info("Sip Server UDP 启动成功 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "]");
return udpSipProvider;
}
}

9
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java

@ -194,12 +194,13 @@ public class DigestServerAuthenticationHelper {
// 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
// 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
//String cNonce = authHeader.getCNonce();
String cnonce = authHeader.getCNonce();
// nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量
int nc = authHeader.getNonceCount();
String ncStr = new DecimalFormat("00000000").format(nc);
// String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
String ncStr = String.format("%08x", nc).toUpperCase();
// String ncStr = new DecimalFormat("00000000").format(nc);
// String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
String A1 = username + ":" + realm + ":" + pass;
String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
@ -212,7 +213,7 @@ public class DigestServerAuthenticationHelper {
String HA2 = toHexString(mdbytes);
logger.debug("HA1: " + HA1);
logger.debug("HA2: " + HA2);
String cnonce = authHeader.getCNonce();
// String cnonce = authHeader.getCNonce();
logger.debug("nonce: " + nonce);
logger.debug("nc: " + ncStr);
logger.debug("cnonce: " + cnonce);

16
src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java

@ -1,5 +1,7 @@
package com.genersoft.iot.vmp.gb28181.auth;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -7,20 +9,24 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
/**
* @Description:注册逻辑处理当设备注册后触发逻辑
* @description:注册逻辑处理当设备注册后触发逻辑
* @author: swwheihei
* @date: 2020年5月8日 下午9:41:46
*/
@Component
public class RegisterLogicHandler {
private Logger logger = LoggerFactory.getLogger(RegisterLogicHandler.class);
@Autowired
private SIPCommander cmder;
public void onRegister(Device device) {
// TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口
cmder.deviceInfoQuery(device);
cmder.catalogQuery(device, null);
// 只有第一次注册时调用查询设备信息,如需更新调用更新API接口
if (device.isFirsRegister()) {
logger.info("[{}] 首次注册,查询设备信息以及通道信息", device.getDeviceId());
cmder.deviceInfoQuery(device);
cmder.catalogQuery(device, null);
}
}
}

60
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@ -60,7 +60,7 @@ public class Device {
/**
* 在线
*/
private int online;
private Integer online;
/**
@ -94,6 +94,28 @@ public class Device {
*/
private String updateTime;
/**
* 设备使用的媒体id, 默认为null
*/
private String mediaServerId;
/**
* 首次注册
*/
private boolean firsRegister;
/**
* 字符集, 支持 utf-8 gb2312
*/
private String charset ;
/**
* 目录订阅周期0为不订阅
*/
private int subscribeCycleForCatalog ;
public String getDeviceId() {
return deviceId;
}
@ -174,11 +196,11 @@ public class Device {
this.hostAddress = hostAddress;
}
public int getOnline() {
public Integer getOnline() {
return online;
}
public void setOnline(int online) {
public void setOnline(Integer online) {
this.online = online;
}
@ -229,4 +251,36 @@ public class Device {
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
public boolean isFirsRegister() {
return firsRegister;
}
public void setFirsRegister(boolean firsRegister) {
this.firsRegister = firsRegister;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public int getSubscribeCycleForCatalog() {
return subscribeCycleForCatalog;
}
public void setSubscribeCycleForCatalog(int subscribeCycleForCatalog) {
this.subscribeCycleForCatalog = subscribeCycleForCatalog;
}
}

26
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java

@ -3,11 +3,21 @@ package com.genersoft.iot.vmp.gb28181.bean;
public class DeviceAlarm {
/**
* 数据库id
*/
private String id;
/**
* 设备Id
*/
private String deviceId;
/**
* 通道Id
*/
private String channelId;
/**
* 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级 警情-
*/
@ -45,6 +55,14 @@ public class DeviceAlarm {
private String alarmType;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getDeviceId() {
return deviceId;
}
@ -108,4 +126,12 @@ public class DeviceAlarm {
public void setAlarmType(String alarmType) {
this.alarmType = alarmType;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
}

9
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java

@ -9,6 +9,7 @@ public class GbStream extends PlatformGbStream{
private String stream;
private String gbId;
private String name;
private String mediaServerId;
private double longitude;
private double latitude;
private String streamType;
@ -77,4 +78,12 @@ public class GbStream extends PlatformGbStream{
public void setStatus(boolean status) {
this.status = status;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
}

15
src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.bean;
/**
* @Description: 移动位置bean
* @description: 移动位置bean
* @author: lawrencehj
* @date: 2021年1月23日
*/
@ -12,6 +12,11 @@ public class MobilePosition {
*/
private String deviceId;
/**
* 通道Id
*/
private String channelId;
/**
* 设备名称
*/
@ -163,4 +168,12 @@ public class MobilePosition {
public void setCnLat(String cnLat) {
this.cnLat = cnLat;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
}

13
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java

@ -6,14 +6,16 @@ package com.genersoft.iot.vmp.gb28181.bean;
import java.util.List;
/**
* @Description:设备录像信息bean
* @description:设备录像信息bean
* @author: swwheihei
* @date: 2020年5月8日 下午2:05:56
*/
public class RecordInfo {
private String deviceId;
private String channelId;
private String name;
private int sumNum;
@ -52,4 +54,11 @@ public class RecordInfo {
this.recordList = recordList;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
}

2
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java

@ -8,7 +8,7 @@ import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description:设备录像bean
* @description:设备录像bean
* @author: swwheihei
* @date: 2020年5月8日 下午2:06:54
*/

13
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java

@ -66,6 +66,11 @@ public class SendRtpItem {
*/
private int localPort;
/**
* 使用的流媒体
*/
private String mediaServerId;
public String getIp() {
return ip;
}
@ -161,4 +166,12 @@ public class SendRtpItem {
public void setTcpActive(boolean tcpActive) {
this.tcpActive = tcpActive;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
}

68
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java

@ -0,0 +1,68 @@
package com.genersoft.iot.vmp.gb28181.bean;
public class SsrcTransaction {
private String deviceId;
private String channelId;
private String ssrc;
private String streamId;
private byte[] transaction;
private byte[] dialog;
private String mediaServerId;
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
}
public String getChannelId() {
return channelId;
}
public void setChannelId(String channelId) {
this.channelId = channelId;
}
public String getSsrc() {
return ssrc;
}
public void setSsrc(String ssrc) {
this.ssrc = ssrc;
}
public String getStreamId() {
return streamId;
}
public void setStreamId(String streamId) {
this.streamId = streamId;
}
public byte[] getTransaction() {
return transaction;
}
public void setTransaction(byte[] transaction) {
this.transaction = transaction;
}
public byte[] getDialog() {
return dialog;
}
public void setDialog(byte[] dialog) {
this.dialog = dialog;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
}

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/DeviceOffLineDetector.java

@ -7,7 +7,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/**
* @Description:设备离在线状态检测器用于检测设备状态
* @description:设备离在线状态检测器用于检测设备状态
* @author: swwheihei
* @date: 2020年5月13日 下午2:40:29
*/

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java

@ -13,7 +13,7 @@ import com.genersoft.iot.vmp.gb28181.event.offline.OfflineEvent;
import com.genersoft.iot.vmp.gb28181.event.online.OnlineEvent;
/**
* @Description:Event事件通知推送器支持推送在线事件离线事件
* @description:Event事件通知推送器支持推送在线事件离线事件
* @author: swwheihei
* @date: 2020年5月6日 上午11:30:50
*/

86
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java

@ -1,38 +1,120 @@
package com.genersoft.iot.vmp.gb28181.event;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import javax.sip.ResponseEvent;
import javax.sip.*;
import java.util.Calendar;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class SipSubscribe {
private final Logger logger = LoggerFactory.getLogger(SipSubscribe.class);
private Map<String, SipSubscribe.Event> errorSubscribes = new ConcurrentHashMap<>();
private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
private Map<String, Date> timeSubscribes = new ConcurrentHashMap<>();
// @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次
@Scheduled(cron="0 0 * * * ?") //每小时执行一次, 每个整点
public void execute(){
logger.info("[定时任务] 清理过期的订阅信息");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) - 1);
for (String key : timeSubscribes.keySet()) {
if (timeSubscribes.get(key).before(calendar.getTime())){
logger.info("[定时任务] 清理过期的订阅信息: {}", key);
errorSubscribes.remove(key);
okSubscribes.remove(key);
timeSubscribes.remove(key);
}
}
}
public interface Event {
void response(ResponseEvent event);
void response(EventResult eventResult);
}
public static class EventResult<EventObject>{
public int statusCode;
public String type;
public String msg;
public String callId;
public Dialog dialog;
public EventObject event;
public EventResult() {
}
public EventResult(EventObject event) {
this.event = event;
if (event instanceof ResponseEvent) {
ResponseEvent responseEvent = (ResponseEvent)event;
this.type = "response";
this.msg = responseEvent.getResponse().getReasonPhrase();
this.statusCode = responseEvent.getResponse().getStatusCode();
this.callId = responseEvent.getDialog().getCallId().getCallId();
this.dialog = responseEvent.getDialog();
}else if (event instanceof TimeoutEvent) {
TimeoutEvent timeoutEvent = (TimeoutEvent)event;
this.type = "timeout";
this.msg = "消息超时未回复";
this.statusCode = -1024;
this.callId = timeoutEvent.getClientTransaction().getDialog().getCallId().getCallId();
this.dialog = timeoutEvent.getClientTransaction().getDialog();
}else if (event instanceof TransactionTerminatedEvent) {
TransactionTerminatedEvent transactionTerminatedEvent = (TransactionTerminatedEvent)event;
this.type = "transactionTerminated";
this.msg = "事务已结束";
this.statusCode = -1024;
this.callId = transactionTerminatedEvent.getClientTransaction().getDialog().getCallId().getCallId();
this.dialog = transactionTerminatedEvent.getClientTransaction().getDialog();
}else if (event instanceof DialogTerminatedEvent) {
DialogTerminatedEvent dialogTerminatedEvent = (DialogTerminatedEvent)event;
this.type = "dialogTerminated";
this.msg = "会话已结束";
this.statusCode = -1024;
this.callId = dialogTerminatedEvent.getDialog().getCallId().getCallId();
this.dialog = dialogTerminatedEvent.getDialog();
}
}
}
public void addErrorSubscribe(String key, SipSubscribe.Event event) {
errorSubscribes.put(key, event);
timeSubscribes.put(key, new Date());
}
public void addOkSubscribe(String key, SipSubscribe.Event event) {
okSubscribes.put(key, event);
timeSubscribes.put(key, new Date());
}
public SipSubscribe.Event getErrorSubscribe(String key) {
return errorSubscribes.get(key);
}
public void removeErrorSubscribe(String key) {
errorSubscribes.remove(key);
timeSubscribes.remove(key);
}
public SipSubscribe.Event getOkSubscribe(String key) {
return okSubscribes.get(key);
}
public void removeOkSubscribe(String key) {
okSubscribes.remove(key);
timeSubscribes.remove(key);
}
public int getErrorSubscribesSize(){
return errorSubscribes.size();
}

6
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepaliveTimeoutListenerForPlatform.java

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei
* @date: 2020年5月6日 上午11:35:46
*/
@ -39,10 +39,6 @@ public class KeepaliveTimeoutListenerForPlatform extends KeyExpirationEventMessa
// 获取失效的key
String expiredKey = message.toString();
logger.debug(expiredKey);
if(!expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)){
logger.debug("收到redis过期监听,但开头不是"+VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX+",忽略");
return;
}
// 平台心跳到期,需要重发, 判断是否已经多次未收到心跳回复, 多次未收到,则重新发起注册, 注册尝试多次未得到回复,则认为平台离线
if (expiredKey.startsWith(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX)) {
String platformGBId = expiredKey.substring(VideoManagerConstants.PLATFORM_KEEPLIVEKEY_PREFIX.length(),expiredKey.length());

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/KeepliveTimeoutListener.java

@ -12,7 +12,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
/**
* @Description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @description:设备心跳超时监听,借助redis过期特性进行监听监听到说明设备心跳超时发送离线事件
* @author: swwheihei
* @date: 2020年5月6日 上午11:35:46
*/

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEvent.java

@ -3,7 +3,7 @@ package com.genersoft.iot.vmp.gb28181.event.offline;
import org.springframework.context.ApplicationEvent;
/**
* @Description: 离线事件类
* @description: 离线事件类
* @author: swwheihei
* @date: 2020年5月6日 上午11:33:13
*/

7
src/main/java/com/genersoft/iot/vmp/gb28181/event/offline/OfflineEventListener.java

@ -11,8 +11,8 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/**
* @Description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
* @description: 离线事件监听器监听到离线后修改设备离在线状态 设备离线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.RegisterRequestProcessor}
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.event.offline.OfflineEventListener}
* @author: swwheihei
* @date: 2020年5月6日 下午1:51:23
@ -54,5 +54,8 @@ public class OfflineEventListener implements ApplicationListener<OfflineEvent> {
// 处理离线监听
storager.outline(event.getDeviceId());
// TODO 离线取消订阅
}
}

2
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEvent.java

@ -4,7 +4,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device;
import org.springframework.context.ApplicationEvent;
/**
* @Description: 在线事件类
* @description: 在线事件类
* @author: swwheihei
* @date: 2020年5月6日 上午11:32:56
*/

14
src/main/java/com/genersoft/iot/vmp/gb28181/event/online/OnlineEventListener.java

@ -13,12 +13,11 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源
* 1设备主动注销发送注销指令{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor}
* 2设备未知原因离线心跳超时,{@link com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor}
* @description: 在线事件监听器监听到离线后修改设备离在线状态 设备在线有两个来源
* 1设备主动注销发送注销指令
* 2设备未知原因离线心跳超时
* @author: swwheihei
* @date: 2020年5月6日 下午1:51:23
*/
@ -52,7 +51,7 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
case VideoManagerConstants.EVENT_ONLINE_REGISTER:
// 超时时间
redis.set(key, event.getDevice().getDeviceId(), sipConfig.getKeepaliveTimeOut());
device.setRegisterTime(format.format(new Date(System.currentTimeMillis())));
device.setRegisterTime(format.format(System.currentTimeMillis()));
break;
// 设备主动发送心跳触发的在线事件
case VideoManagerConstants.EVENT_ONLINE_KEEPLIVE:
@ -63,7 +62,7 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
} else {
redis.expire(key, sipConfig.getKeepaliveTimeOut());
}
device.setKeepaliveTime(format.format(new Date(System.currentTimeMillis())));
device.setKeepaliveTime(format.format(System.currentTimeMillis()));
break;
// 设备主动发送消息触发的在线事件
case VideoManagerConstants.EVENT_ONLINE_MESSAGE:
@ -74,5 +73,8 @@ public class OnlineEventListener implements ApplicationListener<OnlineEvent> {
device.setOnline(1);
// 处理上线监听
storager.updateDevice(device);
// TODO 上线添加订阅
}
}

6
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformKeepaliveExpire/PlatformKeepaliveExpireEventLister.java

@ -18,7 +18,7 @@ import javax.sip.ResponseEvent;
import javax.sip.message.Response;
/**
* @Description: 平台心跳超时事件
* @description: 平台心跳超时事件
* @author: panll
* @date: 2020年11月5日 10:00
*/
@ -75,8 +75,8 @@ public class PlatformKeepaliveExpireEventLister implements ApplicationListener<P
redisCatchStorage.updatePlatformKeepalive(parentPlatform);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
sipSubscribe.addOkSubscribe(callId, (ResponseEvent responseEvent) ->{
if (responseEvent.getResponse().getStatusCode() == Response.OK) {
sipSubscribe.addOkSubscribe(callId, (SipSubscribe.EventResult eventResult) ->{
if (eventResult.statusCode == Response.OK) {
// 收到心跳响应信息,
parentPlatformCatch.setKeepAliveReply(0);
redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);

28
src/main/java/com/genersoft/iot/vmp/gb28181/event/platformNotRegister/PlatformNotRegisterEventLister.java

@ -6,6 +6,8 @@ import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.slf4j.Logger;
@ -17,7 +19,7 @@ import org.springframework.stereotype.Component;
import java.util.*;
/**
* @Description: 平台未注册事件,来源有二:
* @description: 平台未注册事件,来源有二:
* 1平台新添加
* 2平台心跳超时
* @author: panll
@ -32,6 +34,8 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SIPCommanderFroPlatform sipCommanderFroPlatform;
@ -62,22 +66,24 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
logger.info("停止[ {} ]的所有推流", event.getPlatformGbID());
StringBuilder app = new StringBuilder();
StringBuilder stream = new StringBuilder();
for (int i = 0; i < sendRtpItems.size(); i++) {
for (SendRtpItem sendRtpItem : sendRtpItems) {
if (app.length() != 0) {
app.append(",");
}
app.append(sendRtpItems.get(i).getApp());
app.append(sendRtpItem.getApp());
if (stream.length() != 0) {
stream.append(",");
}
stream.append(sendRtpItems.get(i).getStreamId());
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItems.get(i).getChannelId());
stream.append(sendRtpItem.getStreamId());
redisCatchStorage.deleteSendRTPServer(event.getPlatformGbID(), sendRtpItem.getChannelId());
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
Map<String, Object> param = new HashMap<>();
param.put("vhost", "__defaultVhost__");
param.put("app", app.toString());
param.put("stream", stream.toString());
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
}
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app", app.toString());
param.put("stream", stream.toString());
zlmrtpServerFactory.stopSendRtpStream(param);
}
@ -94,6 +100,6 @@ public class PlatformNotRegisterEventLister implements ApplicationListener<Platf
logger.info("再次向平台注册,平台国标ID:" + event.getPlatformGbID());
sipCommanderFroPlatform.register(parentPlatform, null, okEvent);
}
}, config.getRegisterTimeInterval(), config.getRegisterTimeInterval());//十五秒后再次发起注册
}, config.getRegisterTimeInterval()* 1000, config.getRegisterTimeInterval()* 1000);//十五秒后再次发起注册
}
}

140
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcConfig.java

@ -0,0 +1,140 @@
package com.genersoft.iot.vmp.gb28181.session;
import com.genersoft.iot.vmp.utils.ConfigConst;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class SsrcConfig {
/**
* zlm流媒体服务器Id
*/
private String mediaServerId;
private String ssrcPrefix;
/**
* zlm流媒体服务器已用会话句柄
*/
private List<String> isUsed;
/**
* zlm流媒体服务器可用会话句柄
*/
private List<String> notUsed;
public SsrcConfig() {
}
public SsrcConfig(String mediaServerId, Set<String> usedSet, String sipDomain) {
this.mediaServerId = mediaServerId;
this.isUsed = new ArrayList<>();
this.ssrcPrefix = sipDomain.substring(3, 8);
this.notUsed = new ArrayList<>();
for (int i = 1; i < ConfigConst.MAX_STRTEAM_COUNT; i++) {
String ssrc;
if (i < 10) {
ssrc = "000" + i;
} else if (i < 100) {
ssrc = "00" + i;
} else if (i < 1000) {
ssrc = "0" + i;
} else {
ssrc = String.valueOf(i);
}
if (null == usedSet || !usedSet.contains(ssrc)) {
this.notUsed.add(ssrc);
} else {
this.isUsed.add(ssrc);
}
}
}
/**
* 获取视频预览的SSRC值,第一位固定为0
* @return ssrc
*/
public String getPlaySsrc() {
return "0" + getSsrcPrefix() + getSN();
}
/**
* 获取录像回放的SSRC值,第一位固定为1
*
*/
public String getPlayBackSsrc() {
return "1" + getSsrcPrefix() + getSN();
}
/**
* 释放ssrc主要用完的ssrc一定要释放否则会耗尽
* @param ssrc 需要重置的ssrc
*/
public void releaseSsrc(String ssrc) {
if (ssrc == null) {
return;
}
String sn = ssrc.substring(6);
try {
isUsed.remove(sn);
notUsed.add(sn);
}catch (NullPointerException e){
System.out.printf("11111");
}
}
/**
* 获取后四位数SN,随机数
*
*/
private String getSN() {
String sn = null;
int index = 0;
if (notUsed.size() == 0) {
throw new RuntimeException("ssrc已经用完");
} else if (notUsed.size() == 1) {
sn = notUsed.get(0);
} else {
index = new Random().nextInt(notUsed.size() - 1);
sn = notUsed.get(index);
}
notUsed.remove(index);
isUsed.add(sn);
return sn;
}
public String getSsrcPrefix() {
return ssrcPrefix;
}
public String getMediaServerId() {
return mediaServerId;
}
public void setMediaServerId(String mediaServerId) {
this.mediaServerId = mediaServerId;
}
public void setSsrcPrefix(String ssrcPrefix) {
this.ssrcPrefix = ssrcPrefix;
}
public List<String> getIsUsed() {
return isUsed;
}
public void setIsUsed(List<String> isUsed) {
this.isUsed = isUsed;
}
public List<String> getNotUsed() {
return notUsed;
}
public void setNotUsed(List<String> notUsed) {
this.notUsed = notUsed;
}
}

101
src/main/java/com/genersoft/iot/vmp/gb28181/session/SsrcUtil.java

@ -1,101 +0,0 @@
package com.genersoft.iot.vmp.gb28181.session;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:SIP信令中的SSRC工具类SSRC值由10位十进制整数组成的字符串第一位为0代表实况为1则代表回放第二位至第六位由监控域ID的第4位到第8位组成最后4位为不重复的4个整数
* @author: swwheihei
* @date: 2020年5月10日 上午11:57:57
*/
public class SsrcUtil {
private final static Logger logger = LoggerFactory.getLogger(SsrcUtil.class);
private static String ssrcPrefix;
private static List<String> isUsed;
private static List<String> notUsed;
private static void init() {
SipConfig sipConfig = (SipConfig) SpringBeanFactory.getBean("sipConfig");
ssrcPrefix = sipConfig.getSipDomain().substring(3, 8);
isUsed = new ArrayList<String>();
notUsed = new ArrayList<String>();
for (int i = 1; i < 10000; i++) {
if (i < 10) {
notUsed.add("000" + i);
} else if (i < 100) {
notUsed.add("00" + i);
} else if (i < 1000) {
notUsed.add("0" + i);
} else {
notUsed.add(String.valueOf(i));
}
}
}
/**
* 获取视频预览的SSRC值,第一位固定为0
*
*/
public static String getPlaySsrc() {
return "0" + getSsrcPrefix() + getSN();
}
/**
* 获取录像回放的SSRC值,第一位固定为1
*
*/
public static String getPlayBackSsrc() {
return "1" + getSsrcPrefix() + getSN();
}
/**
* 释放ssrc主要用完的ssrc一定要释放否则会耗尽
*
*/
public static void releaseSsrc(String ssrc) {
if (ssrc == null) {
logger.error("要释放ssrc为null");
return;
}
String sn = ssrc.substring(6);
isUsed.remove(sn);
notUsed.add(sn);
}
/**
* 获取后四位数SN,随机数
*
*/
private static String getSN() {
String sn = null;
int index = 0;
if (notUsed.size() == 0) {
throw new RuntimeException("ssrc已经用完");
} else if (notUsed.size() == 1) {
sn = notUsed.get(0);
} else {
index = new Random().nextInt(notUsed.size() - 1);
sn = notUsed.get(index);
}
notUsed.remove(index);
isUsed.add(sn);
return sn;
}
private static String getSsrcPrefix() {
if (ssrcPrefix == null) {
init();
}
return ssrcPrefix;
}
}

101
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java

@ -1,51 +1,106 @@
package com.genersoft.iot.vmp.gb28181.session;
import java.util.concurrent.ConcurrentHashMap;
import java.util.ArrayList;
import java.util.List;
import javax.sip.ClientTransaction;
import javax.sip.Dialog;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.utils.SerializeUtils;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import gov.nist.javax.sip.stack.SIPDialog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Description:视频流session管理器管理视频预览预览回放的通信句柄
* @description:视频流session管理器管理视频预览预览回放的通信句柄
* @author: swwheihei
* @date: 2020年5月13日 下午4:03:02
*/
@Component
public class VideoStreamSessionManager {
private ConcurrentHashMap<String, ClientTransaction> sessionMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, String> ssrcMap = new ConcurrentHashMap<>();
private ConcurrentHashMap<String, String> streamIdMap = new ConcurrentHashMap<>();
@Autowired
private RedisUtil redisUtil;
public String createPlaySsrc(){
return SsrcUtil.getPlaySsrc();
}
public String createPlayBackSsrc(){
return SsrcUtil.getPlayBackSsrc();
public void put(String deviceId, String channelId ,String ssrc, String streamId, String mediaServerId, ClientTransaction transaction){
SsrcTransaction ssrcTransaction = new SsrcTransaction();
ssrcTransaction.setDeviceId(deviceId);
ssrcTransaction.setChannelId(channelId);
ssrcTransaction.setStreamId(streamId);
byte[] transactionByteArray = SerializeUtils.serialize(transaction);
ssrcTransaction.setTransaction(transactionByteArray);
ssrcTransaction.setSsrc(ssrc);
ssrcTransaction.setMediaServerId(mediaServerId);
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId, ssrcTransaction);
}
public void put(String deviceId, String channelId ,String ssrc, String streamId, ClientTransaction transaction){
sessionMap.put(deviceId + "_" + channelId, transaction);
ssrcMap.put(deviceId + "_" + channelId, ssrc);
streamIdMap.put(deviceId + "_" + channelId, streamId);
public void put(String deviceId, String channelId , Dialog dialog){
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction != null) {
byte[] dialogByteArray = SerializeUtils.serialize(dialog);
ssrcTransaction.setDialog(dialogByteArray);
}
redisUtil.set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId, ssrcTransaction);
}
public ClientTransaction getTransaction(String deviceId, String channelId){
return sessionMap.get(deviceId + "_" + channelId);
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return null;
byte[] transactionByteArray = ssrcTransaction.getTransaction();
ClientTransaction clientTransaction = (ClientTransaction)SerializeUtils.deSerialize(transactionByteArray);
return clientTransaction;
}
public SIPDialog getDialog(String deviceId, String channelId){
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return null;
byte[] dialogByteArray = ssrcTransaction.getDialog();
if (dialogByteArray == null) return null;
SIPDialog dialog = (SIPDialog)SerializeUtils.deSerialize(dialogByteArray);
return dialog;
}
public SsrcTransaction getSsrcTransaction(String deviceId, String channelId){
SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId);
return ssrcTransaction;
}
public String getStreamId(String deviceId, String channelId){
return streamIdMap.get(deviceId + "_" + channelId);
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return null;
return ssrcTransaction.getStreamId();
}
public String getMediaServerId(String deviceId, String channelId){
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return null;
return ssrcTransaction.getMediaServerId();
}
public String getSSRC(String deviceId, String channelId){
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return null;
return ssrcTransaction.getSsrc();
}
public void remove(String deviceId, String channelId) {
sessionMap.remove(deviceId + "_" + channelId);
if (ssrcMap.get(deviceId + "_" + channelId) != null) {
SsrcUtil.releaseSsrc(ssrcMap.get(deviceId + "_" + channelId));
SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction == null) return;
redisUtil.del(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + deviceId + "_" + channelId);
}
public List<SsrcTransaction> getAllSsrc() {
List<Object> ssrcTransactionKeys = redisUtil.scan(String.format("%s_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX));
List<SsrcTransaction> result= new ArrayList<>();
for (int i = 0; i < ssrcTransactionKeys.size(); i++) {
String key = (String)ssrcTransactionKeys.get(i);
SsrcTransaction ssrcTransaction = (SsrcTransaction)redisUtil.get(key);
result.add(ssrcTransaction);
}
ssrcMap.remove(deviceId + "_" + channelId);
streamIdMap.remove(deviceId + "_" + channelId);
return result;
}
}

229
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java

@ -1,229 +0,0 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import javax.sip.RequestEvent;
import javax.sip.ResponseEvent;
import javax.sip.SipProvider;
import javax.sip.header.CSeqHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
import com.genersoft.iot.vmp.service.IPlayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.AckRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.ByeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.CancelRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.InviteRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.NotifyRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.OtherRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.RegisterRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.SubscribeRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.ByeResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.CancelResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.InviteResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.response.impl.OtherResponseProcessor;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
/**
* @Description: SIP信令处理分配
* @author: swwheihei
* @date: 2020年5月3日 下午4:24:37
*/
@Component
public class SIPProcessorFactory {
// private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
@Autowired
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private EventPublisher publisher;
@Autowired
private SIPCommander cmder;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private RedisUtil redis;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private InviteResponseProcessor inviteResponseProcessor;
@Autowired
private ByeResponseProcessor byeResponseProcessor;
@Autowired
private CancelResponseProcessor cancelResponseProcessor;
@Autowired
@Lazy
private RegisterResponseProcessor registerResponseProcessor;
@Autowired
private OtherResponseProcessor otherResponseProcessor;
@Autowired
private IPlayService playService;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider tcpSipProvider;
// 注:这里使用注解会导致循环依赖注入,暂用springBean
private SipProvider udpSipProvider;
public ISIPRequestProcessor createRequestProcessor(RequestEvent evt) {
Request request = evt.getRequest();
String method = request.getMethod();
// logger.info("接收到消息:"+request.getMethod());
// sipSubscribe.getSubscribe(evt.getServerTransaction().getBranchId()).response(evt);
if (Request.INVITE.equals(method)) {
InviteRequestProcessor processor = new InviteRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setPlayService(playService);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.REGISTER.equals(method)) {
RegisterRequestProcessor processor = new RegisterRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setHandler(handler);
processor.setPublisher(publisher);
processor.setSipConfig(sipConfig);
processor.setVideoManagerStorager(storager);
return processor;
} else if (Request.SUBSCRIBE.equals(method)) {
SubscribeRequestProcessor processor = new SubscribeRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.ACK.equals(method)) {
AckRequestProcessor processor = new AckRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
return processor;
} else if (Request.BYE.equals(method)) {
ByeRequestProcessor processor = new ByeRequestProcessor();
processor.setRequestEvent(evt);
processor.setRedisCatchStorage(redisCatchStorage);
processor.setZlmrtpServerFactory(zlmrtpServerFactory);
processor.setSIPCommander(cmder);
return processor;
} else if (Request.CANCEL.equals(method)) {
CancelRequestProcessor processor = new CancelRequestProcessor();
processor.setRequestEvent(evt);
return processor;
} else if (Request.MESSAGE.equals(method)) {
MessageRequestProcessor processor = new MessageRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setCmderFroPlatform(cmderFroPlatform);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else if (Request.NOTIFY.equalsIgnoreCase(method)) {
NotifyRequestProcessor processor = new NotifyRequestProcessor();
processor.setRequestEvent(evt);
processor.setTcpSipProvider(getTcpSipProvider());
processor.setUdpSipProvider(getUdpSipProvider());
processor.setPublisher(publisher);
processor.setRedis(redis);
processor.setDeferredResultHolder(deferredResultHolder);
processor.setOffLineDetector(offLineDetector);
processor.setCmder(cmder);
processor.setStorager(storager);
processor.setRedisCatchStorage(redisCatchStorage);
return processor;
} else {
OtherRequestProcessor processor = new OtherRequestProcessor();
processor.setRequestEvent(evt);
return processor;
}
}
public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
Response response = evt.getResponse();
CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
if(Request.INVITE.equals(method)){
return inviteResponseProcessor;
} else if (Request.BYE.equals(method)) {
return byeResponseProcessor;
} else if (Request.CANCEL.equals(method)) {
return cancelResponseProcessor;
}else if (Request.REGISTER.equals(method)) {
return registerResponseProcessor;
} else {
return otherResponseProcessor;
}
}
private SipProvider getTcpSipProvider() {
if (tcpSipProvider == null) {
tcpSipProvider = (SipProvider) SpringBeanFactory.getBean("tcpSipProvider");
}
return tcpSipProvider;
}
private SipProvider getUdpSipProvider() {
if (udpSipProvider == null) {
udpSipProvider = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
}
return udpSipProvider;
}
}

160
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java

@ -0,0 +1,160 @@
package com.genersoft.iot.vmp.gb28181.transmit;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.response.ISIPResponseProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.*;
import javax.sip.header.CSeqHeader;
import javax.sip.header.CallIdHeader;
import javax.sip.message.Response;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @description: SIP信令处理类观察者
* @author: panlinlin
* @date: 2021年11月5日 下午1532
*/
@Component
public class SIPProcessorObserver implements SipListener {
private final static Logger logger = LoggerFactory.getLogger(SIPProcessorObserver.class);
private static Map<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>();
private static Map<String, ISIPResponseProcessor> responseProcessorMap = new ConcurrentHashMap<>();
private static ITimeoutProcessor timeoutProcessor;
@Autowired
private SipSubscribe sipSubscribe;
/**
* 添加 request订阅
* @param method 方法名
* @param processor 处理程序
*/
public void addRequestProcessor(String method, ISIPRequestProcessor processor) {
requestProcessorMap.put(method, processor);
}
/**
* 添加 response订阅
* @param method 方法名
* @param processor 处理程序
*/
public void addResponseProcessor(String method, ISIPResponseProcessor processor) {
responseProcessorMap.put(method, processor);
}
/**
* 添加 超时事件订阅
* @param processor 处理程序
*/
public void addTimeoutProcessor(ITimeoutProcessor processor) {
this.timeoutProcessor = processor;
}
/**
* 分发RequestEvent事件
* @param requestEvent RequestEvent事件
*/
@Override
public void processRequest(RequestEvent requestEvent) {
String method = requestEvent.getRequest().getMethod();
ISIPRequestProcessor sipRequestProcessor = requestProcessorMap.get(method);
if (sipRequestProcessor == null) {
logger.warn("不支持方法{}的request", method);
return;
}
requestProcessorMap.get(requestEvent.getRequest().getMethod()).process(requestEvent);
}
/**
* 分发ResponseEvent事件
* @param responseEvent responseEvent事件
*/
@Override
public void processResponse(ResponseEvent responseEvent) {
logger.debug(responseEvent.getResponse().toString());
// CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
// String method = cseqHeader.getMethod();
// ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
// if (sipRequestProcessor == null) {
// logger.warn("不支持方法{}的response", method);
// return;
// }
// sipRequestProcessor.process(responseEvent);
Response response = responseEvent.getResponse();
logger.debug(responseEvent.getResponse().toString());
int status = response.getStatusCode();
if (((status >= 200) && (status < 300)) || status == 401) { // Success!
// ISIPResponseProcessor processor = processorFactory.createResponseProcessor(evt);
CSeqHeader cseqHeader = (CSeqHeader) responseEvent.getResponse().getHeader(CSeqHeader.NAME);
String method = cseqHeader.getMethod();
ISIPResponseProcessor sipRequestProcessor = responseProcessorMap.get(method);
if (sipRequestProcessor != null) {
sipRequestProcessor.process(responseEvent);
}
if (responseEvent.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult);
}
}
}
} else if ((status >= 100) && (status < 200)) {
// 增加其它无需回复的响应,如101、180等
} else {
logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
if (responseEvent.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME);
if (callIdHeader != null) {
SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
if (subscribe != null) {
SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(responseEvent);
subscribe.response(eventResult);
}
}
}
}
}
/**
* 向超时订阅发送消息
* @param timeoutEvent timeoutEvent事件
*/
@Override
public void processTimeout(TimeoutEvent timeoutEvent) {
if(timeoutProcessor != null) {
timeoutProcessor.process(timeoutEvent);
}
}
@Override
public void processIOException(IOExceptionEvent exceptionEvent) {
}
@Override
public void processTransactionTerminated(TransactionTerminatedEvent transactionTerminatedEvent) {
}
@Override
public void processDialogTerminated(DialogTerminatedEvent dialogTerminatedEvent) {
}
}

21
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java

@ -1,17 +1,16 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import com.genersoft.iot.vmp.gb28181.transmit.request.impl.MessageRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.RecordInfoResponseMessageHandler;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.TimeUnit;
@SuppressWarnings("unchecked")
public class CheckForAllRecordsThread extends Thread {
@ -54,13 +53,11 @@ public class CheckForAllRecordsThread extends Thread {
// 自然顺序排序, 元素进行升序排列
this.recordInfo.getRecordList().sort(Comparator.naturalOrder());
RequestMessage msg = new RequestMessage();
String deviceId = recordInfo.getDeviceId();
msg.setDeviceId(deviceId);
msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO);
msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getChannelId());
msg.setData(recordInfo);
deferredResultHolder.invokeResult(msg);
deferredResultHolder.invokeAllResult(msg);
logger.info("处理完成,返回结果");
MessageRequestProcessor.threadNameList.remove(cacheKey);
RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey);
}
public void setRedis(RedisUtil redis) {

71
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java

@ -1,6 +1,8 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.http.HttpStatus;
@ -9,7 +11,7 @@ import org.springframework.stereotype.Component;
import org.springframework.web.context.request.async.DeferredResult;
/**
* @Description: 异步请求处理
* @description: 异步请求处理
* @author: swwheihei
* @date: 2020年5月8日 下午7:59:05
*/
@ -31,7 +33,7 @@ public class DeferredResultHolder {
public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY";
public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
@ -45,21 +47,72 @@ public class DeferredResultHolder {
public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>();
private Map<String, Map<String, DeferredResult>> map = new ConcurrentHashMap<>();
public void put(String key, DeferredResult result) {
map.put(key, result);
public void put(String key, String id, DeferredResult result) {
Map<String, DeferredResult> deferredResultMap = map.get(key);
if (deferredResultMap == null) {
deferredResultMap = new ConcurrentHashMap<>();
map.put(key, deferredResultMap);
}
deferredResultMap.put(id, result);
}
public DeferredResult get(String key) {
return map.get(key);
public DeferredResult get(String key, String id) {
Map<String, DeferredResult> deferredResultMap = map.get(key);
if (deferredResultMap == null) return null;
return deferredResultMap.get(id);
}
public boolean exist(String key, String id){
if (key == null) return false;
Map<String, DeferredResult> deferredResultMap = map.get(key);
if (id == null) {
return deferredResultMap != null;
}else {
return deferredResultMap != null && deferredResultMap.get(id) != null;
}
}
/**
* 释放单个请求
* @param msg
*/
public void invokeResult(RequestMessage msg) {
DeferredResult result = map.get(msg.getId());
Map<String, DeferredResult> deferredResultMap = map.get(msg.getKey());
if (deferredResultMap == null) {
return;
}
DeferredResult result = deferredResultMap.get(msg.getId());
if (result == null) {
return;
}
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK));
deferredResultMap.remove(msg.getId());
if (deferredResultMap.size() == 0) {
map.remove(msg.getKey());
}
}
/**
* 释放所有的请求
* @param msg
*/
public void invokeAllResult(RequestMessage msg) {
Map<String, DeferredResult> deferredResultMap = map.get(msg.getKey());
if (deferredResultMap == null) {
return;
}
Set<String> ids = deferredResultMap.keySet();
for (String id : ids) {
DeferredResult result = deferredResultMap.get(id);
if (result == null) {
return;
}
result.setResult(new ResponseEntity<>(msg.getData(),HttpStatus.OK));
}
map.remove(msg.getKey());
}
}

28
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java

@ -1,7 +1,7 @@
package com.genersoft.iot.vmp.gb28181.transmit.callback;
/**
* @Description: 请求信息定义
* @description: 请求信息定义
* @author: swwheihei
* @date: 2020年5月8日 下午1:09:18
*/
@ -9,12 +9,10 @@ public class RequestMessage {
private String id;
private String deviceId;
private String type;
private String key;
private Object data;
public String getId() {
return id;
}
@ -23,22 +21,12 @@ public class RequestMessage {
this.id = id;
}
public String getDeviceId() {
return deviceId;
}
public void setDeviceId(String deviceId) {
this.deviceId = deviceId;
this.id = type + deviceId;
}
public String getType() {
return type;
public void setKey(String key) {
this.key = key;
}
public void setType(String type) {
this.type = type;
this.id = type + deviceId;
public String getKey() {
return key;
}
public Object getData() {

32
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java

@ -3,9 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
/**
* @Description:设备能力接口用于定义设备的控制查询能力
* @description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei
* @date: 2020年5月3日 下午9:16:34
*/
@ -90,7 +92,7 @@ public interface ISIPCommander {
* @param device 视频设备
* @param channelId 预览通道
*/
void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 请求回放视频流
@ -100,12 +102,21 @@ public interface ISIPCommander {
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 视频流停止
* 请求历史媒体下载
*
* @param ssrc ssrc
* @param device 视频设备
* @param channelId 预览通道
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
* @param downloadSpeed 下载倍速参数
*/
void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
/**
* 视频流停止
*/
void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent);
void streamByeCmd(String deviceId, String channelId);
@ -289,11 +300,10 @@ public interface ISIPCommander {
*/
boolean alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime);
/**
* 释放rtpserver
* @param device
* @param channelId
* 订阅取消订阅目录信息
* @param device 视频设备
* @return true = 命令发送成功
*/
void closeRTPServer(Device device, String channelId);
boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent);
}

25
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java

@ -15,10 +15,11 @@ import javax.sip.message.Request;
import javax.validation.constraints.NotNull;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* @Description: 平台命令request创造器 TODO 冗余代码太多待优化
* @description: 平台命令request创造器 TODO 冗余代码太多待优化
* @author: panll
* @date: 2020年5月6日 上午9:29:02
*/
@ -38,13 +39,13 @@ public class SIPRequestHeaderPlarformProvider {
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getServerGBId(), parentPlatform.getServerIP() + ":" + parentPlatform.getServerPort());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(),
parentPlatform.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(parentPlatform.getDeviceGBId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
sipConfig.getIp() + ":" + sipConfig.getPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
@ -60,6 +61,12 @@ public class SIPRequestHeaderPlarformProvider {
request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
List<String> agentParam = new ArrayList<>();
agentParam.add("wvp-pro");
UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
request.addHeader(userAgentHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;
@ -68,7 +75,7 @@ public class SIPRequestHeaderPlarformProvider {
public Request createRegisterRequest(@NotNull ParentPlatform platform, long CSeq, String fromTag, String viaTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
String sipAddress = sipConfig.getSipIp() + ":" + sipConfig.getSipPort();
String sipAddress = sipConfig.getIp() + ":" + sipConfig.getPort();
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(platform.getServerGBId(),
platform.getServerIP() + ":" + platform.getServerPort());
@ -103,6 +110,11 @@ public class SIPRequestHeaderPlarformProvider {
ExpiresHeader expires = sipFactory.createHeaderFactory().createExpiresHeader(Integer.parseInt(platform.getExpires()));
request.addHeader(expires);
List<String> agentParam = new ArrayList<>();
agentParam.add("wvp-pro");
UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
request.addHeader(userAgentHeader);
return request;
}
@ -202,6 +214,11 @@ public class SIPRequestHeaderPlarformProvider {
messageFactory.setDefaultContentEncodingCharset("gb2312");
request = messageFactory.createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
toHeader, viaHeaders, maxForwards);
List<String> agentParam = new ArrayList<>();
agentParam.add("wvp-pro");
UserAgentHeader userAgentHeader = sipFactory.createHeaderFactory().createUserAgentHeader(agentParam);
request.addHeader(userAgentHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
request.setContent(content, contentTypeHeader);
return request;

59
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java

@ -18,7 +18,7 @@ import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
/**
* @Description:摄像头命令request创造器 TODO 冗余代码太多待优化
* @description:摄像头命令request创造器 TODO 冗余代码太多待优化
* @author: swwheihei
* @date: 2020年5月6日 上午9:29:02
*/
@ -37,16 +37,16 @@ public class SIPRequestHeaderProvider {
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),
sipConfig.getIp() + ":" + sipConfig.getPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
@ -68,16 +68,16 @@ public class SIPRequestHeaderProvider {
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
//via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
@ -88,32 +88,32 @@ public class SIPRequestHeaderProvider {
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0));
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
}
public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
Request request = null;
//请求行
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId, sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,null);
@ -124,10 +124,13 @@ public class SIPRequestHeaderProvider {
CSeqHeader cSeqHeader = sipFactory.createHeaderFactory().createCSeqHeader(1L, Request.INVITE);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
// Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);
return request;
@ -139,14 +142,14 @@ public class SIPRequestHeaderProvider {
SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(), device.getTransport(), viaTag);
viaHeaders.add(viaHeader);
//from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
//to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getSipDomain());
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(channelId,sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress,toTag);
@ -158,7 +161,7 @@ public class SIPRequestHeaderProvider {
CallIdHeader callIdHeader = sipFactory.createHeaderFactory().createCallIdHeader(callId);
request = sipFactory.createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
return request;
}
@ -169,17 +172,17 @@ public class SIPRequestHeaderProvider {
SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
// via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getIp(), sipConfig.getPort(),
device.getTransport(), viaTag);
viaHeader.setRPort();
viaHeaders.add(viaHeader);
// from
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),
sipConfig.getSipIp() + ":" + sipConfig.getSipPort());
SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getId(),
sipConfig.getIp() + ":" + sipConfig.getPort());
Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = sipFactory.createHeaderFactory().createFromHeader(fromAddress, fromTag);
// to
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getSipDomain());
SipURI toSipURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), sipConfig.getDomain());
Address toAddress = sipFactory.createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = sipFactory.createHeaderFactory().createToHeader(toAddress, toTag);
@ -192,7 +195,7 @@ public class SIPRequestHeaderProvider {
toHeader, viaHeaders, maxForwards);
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), sipConfig.getSipIp()+":"+sipConfig.getSipPort()));
Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getIp()+":"+sipConfig.getPort()));
request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
// Expires

460
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java

@ -1,45 +1,45 @@
package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
import java.text.ParseException;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.conf.MediaConfig;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.bean.SSRCInfo;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.stack.SIPDialog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.CallIdHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.util.HashSet;
/**
* @Description:设备能力接口用于定义设备的控制查询能力
* @description:设备能力接口用于定义设备的控制查询能力
* @author: swwheihei
* @date: 2020年5月3日 下午9:22:48
*/
@ -52,15 +52,13 @@ public class SIPCommander implements ISIPCommander {
@Autowired
private SipConfig sipConfig;
@Lazy
@Autowired
@Qualifier(value="tcpSipProvider")
private SipProvider tcpSipProvider;
private SipProviderImpl tcpSipProvider;
@Lazy
@Autowired
@Qualifier(value="udpSipProvider")
private SipProvider udpSipProvider;
private SipProviderImpl udpSipProvider;
@Autowired
private SIPRequestHeaderProvider headerProvider;
@ -74,15 +72,6 @@ public class SIPCommander implements ISIPCommander {
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private ZLMRESTfulUtils zlmresTfulUtils;
@Autowired
private MediaConfig mediaConfig;
@Autowired
private UserSetup userSetup;
@ -92,9 +81,9 @@ public class SIPCommander implements ISIPCommander {
@Autowired
private SipSubscribe sipSubscribe;
public SipConfig getSipConfig() {
return sipConfig;
}
@Autowired
private IMediaServerService mediaServerService;
/**
* 云台方向放控制使用配置文件中的默认镜头移动速度
@ -106,7 +95,7 @@ public class SIPCommander implements ISIPCommander {
*/
@Override
public boolean ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) {
return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getSpeed(), 0);
return ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
}
/**
@ -132,7 +121,7 @@ public class SIPCommander implements ISIPCommander {
*/
@Override
public boolean ptzZoomCmd(Device device, String channelId, int inOut) {
return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getSpeed());
return ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
}
/**
@ -340,57 +329,40 @@ public class SIPCommander implements ISIPCommander {
* @param errorEvent sip错误订阅
*/
@Override
public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
String streamId = null;
public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
String streamId = ssrcInfo.getStreamId();
try {
if (device == null) return;
String ssrc = streamSession.createPlaySsrc();
if (mediaConfig.isRtpEnable()) {
streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
}else {
streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
}
String streamMode = device.getStreamMode().toUpperCase();
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
if (mediaInfo == null) {
logger.warn("点播时发现ZLM尚未连接...");
return;
}
Integer mediaPort = null;
// 使用动态udp端口
if (mediaConfig.isRtpEnable()) {
mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
}else {
mediaPort = mediaInfo.getRtpProxyPort();
}
logger.info("{} 分配的ZLM为: {} [{}:{}]", streamId, mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
// 添加订阅
JSONObject subscribeKey = new JSONObject();
subscribeKey.put("app", "rtp");
subscribeKey.put("stream", streamId);
subscribeKey.put("regist", true);
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
subscribeKey.put("mediaServerId", mediaServerItem.getId());
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
event.response(json);
event.response(mediaServerItemInUse, json);
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
});
//
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
// content.append("o=" + sipConfig.getSipId() + " 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("o="+ sipConfig.getId()+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
content.append("t=0 0\r\n");
if (userSetup.isSeniorSdp()) {
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@ -411,11 +383,11 @@ public class SIPCommander implements ISIPCommander {
}
}else {
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@ -430,20 +402,25 @@ public class SIPCommander implements ISIPCommander {
}
}
content.append("y="+ssrc+"\r\n");//ssrc
content.append("y="+ssrcInfo.getSsrc()+"\r\n");//ssrc
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrc, callIdHeader);
Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "FromInvt" + tm, null, ssrcInfo.getSsrc(), callIdHeader);
ClientTransaction transaction = transmitRequest(device, request, (e -> {
String finalStreamId = streamId;
transmitRequest(device, request, (e -> {
streamSession.remove(device.getDeviceId(), channelId);
mediaServerService.releaseSsrc(mediaServerItem, ssrcInfo.getSsrc());
errorEvent.response(e);
}));
streamSession.put(device.getDeviceId(), channelId ,ssrc,streamId, transaction);
}), e ->{
streamSession.put(device.getDeviceId(), channelId ,ssrcInfo.getSsrc(), finalStreamId, mediaServerItem.getId(), ((ResponseEvent)e.event).getClientTransaction());
streamSession.put(device.getDeviceId(), channelId , e.dialog);
});
} catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
@ -459,48 +436,153 @@ public class SIPCommander implements ISIPCommander {
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
*/
@Override
public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
, SipSubscribe.Event errorEvent) {
try {
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
String ssrc = streamSession.createPlayBackSsrc();
String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
// 添加订阅
JSONObject subscribeKey = new JSONObject();
subscribeKey.put("app", "rtp");
subscribeKey.put("stream", streamId);
subscribeKey.put("stream", ssrcInfo.getStreamId());
subscribeKey.put("regist", true);
subscribeKey.put("mediaServerId", mediaServerItem.getId());
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey, json->{
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
event.response(json);
event.response(mediaServerItemInUse, json);
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
});
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+sipConfig.getSipId()+" 0 0 IN IP4 "+sipConfig.getSipIp()+"\r\n");
content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
content.append("s=Playback\r\n");
content.append("u="+channelId+":0\r\n");
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
Integer mediaPort = null;
// 使用动态udp端口
if (mediaConfig.isRtpEnable()) {
mediaPort = zlmrtpServerFactory.createRTPServer(streamId);
String streamMode = device.getStreamMode().toUpperCase();
if (userSetup.isSeniorSdp()) {
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
content.append("a=rtpmap:126 H264/90000\r\n");
content.append("a=rtpmap:125 H264S/90000\r\n");
content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
content.append("a=fmtp:99 profile-level-id=3\r\n");
content.append("a=rtpmap:98 H264/90000\r\n");
content.append("a=rtpmap:97 MPEG4/90000\r\n");
if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
content.append("a=setup:passive\r\n");
content.append("a=connection:new\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
content.append("a=setup:active\r\n");
content.append("a=connection:new\r\n");
}
}else {
mediaPort = mediaInfo.getRtpProxyPort();
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("a=rtpmap:98 H264/90000\r\n");
content.append("a=rtpmap:97 MPEG4/90000\r\n");
if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
content.append("a=setup:passive\r\n");
content.append("a=connection:new\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
content.append("a=setup:active\r\n");
content.append("a=connection:new\r\n");
}
}
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
transmitRequest(device, request, errorEvent, okEvent -> {
ResponseEvent responseEvent = (ResponseEvent) okEvent.event;
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), responseEvent.getClientTransaction());
streamSession.put(device.getDeviceId(), channelId, okEvent.dialog);
});
} catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
/**
* 请求历史媒体下载
*
* @param device 视频设备
* @param channelId 预览通道
* @param startTime 开始时间,格式要求yyyy-MM-dd HH:mm:ss
* @param endTime 结束时间,格式要求yyyy-MM-dd HH:mm:ss
* @param downloadSpeed 下载倍速参数
*/
@Override
public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, String startTime, String endTime, String downloadSpeed, ZLMHttpHookSubscribe.Event event
, SipSubscribe.Event errorEvent) {
try {
logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStreamId(), mediaServerItem.getId(), mediaServerItem.getIp(), ssrcInfo.getPort());
// 添加订阅
JSONObject subscribeKey = new JSONObject();
subscribeKey.put("app", "rtp");
subscribeKey.put("stream", ssrcInfo.getStreamId());
subscribeKey.put("regist", true);
subscribeKey.put("mediaServerId", mediaServerItem.getId());
logger.debug("录像回放添加订阅,订阅内容:" + subscribeKey.toString());
subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
(MediaServerItem mediaServerItemInUse, JSONObject json)->{
if (userSetup.isWaitTrack() && json.getJSONArray("tracks") == null) return;
event.response(mediaServerItemInUse, json);
subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
});
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
content.append("s=Download\r\n");
content.append("u="+channelId+":0\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
content.append("t="+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)+" "
+DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) +"\r\n");
String streamMode = device.getStreamMode().toUpperCase();
if (userSetup.isSeniorSdp()) {
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ mediaPort +" RTP/AVP 96 126 125 99 34 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 126 125 99 34 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@ -521,11 +603,11 @@ public class SIPCommander implements ISIPCommander {
}
}else {
if("TCP-PASSIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if ("TCP-ACTIVE".equals(streamMode)) {
content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n");
}else if("UDP".equals(streamMode)) {
content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n");
}
content.append("a=recvonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
@ -539,79 +621,71 @@ public class SIPCommander implements ISIPCommander {
content.append("a=connection:new\r\n");
}
}
content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
content.append("y="+ssrc+"\r\n");//ssrc
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader);
Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
ClientTransaction transaction = transmitRequest(device, request, errorEvent);
streamSession.put(device.getDeviceId(), channelId, ssrc, streamId, transaction);
streamSession.put(device.getDeviceId(), channelId, ssrcInfo.getSsrc(), ssrcInfo.getStreamId(), mediaServerItem.getId(), transaction);
} catch ( SipException | ParseException | InvalidArgumentException e) {
e.printStackTrace();
}
}
/**
* 视频流停止
*
* 视频流停止, 不使用回调
*/
@Override
public void streamByeCmd(String deviceId, String channelId) {
streamByeCmd(deviceId, channelId, null);
}
/**
* 视频流停止
*/
@Override
public void streamByeCmd(String deviceId, String channelId, SipSubscribe.Event okEvent) {
try {
ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId);
// 服务重启后, 无法直接发送bye, 通过手动构建发送
if (transaction == null) {
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
if (streamInfo != null) {
JSONObject mediaList = zlmresTfulUtils.getMediaList(streamInfo.getApp(), streamInfo.getStreamId());
if (mediaList != null) { // 仍在推流才发送
if (mediaList.getInteger("code") == 0) {
JSONArray data = mediaList.getJSONArray("data");
if (data != null && data.size() > 0) {
Device device = storager.queryVideoDevice(deviceId);
if (device != null) {
StreamInfo.TransactionInfo transactionInfo = streamInfo.getTransactionInfo();
try {
Request byteRequest = headerProvider.createByteRequest(device, channelId,
transactionInfo.branch,
transactionInfo.localTag,
transactionInfo.remoteTag,
transactionInfo.callId);
transmitRequest(device, byteRequest);
} catch (InvalidArgumentException e) {
e.printStackTrace();
}
}
}
}
}
redisCatchStorage.stopPlay(streamInfo);
}
logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
if (okEvent != null) {
okEvent.response(null);
okEvent.response(eventResult);
}
return;
}
Dialog dialog = transaction.getDialog();
SIPDialog dialog = streamSession.getDialog(deviceId, channelId);
if (dialog == null) {
logger.warn("[ {} -> {}]停止视频流的时候发现对话已丢失", deviceId, channelId);
return;
}
SipStack sipStack = udpSipProvider.getSipStack();
SIPDialog sipDialog = ((SipStackImpl) sipStack).putDialog(dialog);
if (dialog != sipDialog) {
dialog = sipDialog;
}else {
dialog.setSipProvider(udpSipProvider);
try {
Field sipStackField = SIPDialog.class.getDeclaredField("sipStack");
sipStackField.setAccessible(true);
sipStackField.set(dialog, sipStack);
Field eventListenersField = SIPDialog.class.getDeclaredField("eventListeners");
eventListenersField.setAccessible(true);
eventListenersField.set(dialog, new HashSet<>());
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
Request byeRequest = dialog.createRequest(Request.BYE);
SipURI byeURI = (SipURI) byeRequest.getRequestURI();
SIPRequest request = (SIPRequest)transaction.getRequest();
@ -632,8 +706,13 @@ public class SIPCommander implements ISIPCommander {
}
dialog.sendRequest(clientTransaction);
zlmrtpServerFactory.closeRTPServer(streamSession.getStreamId(deviceId, channelId));
streamSession.remove(deviceId, channelId);
SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId);
if (ssrcTransaction != null) {
MediaServerItem mediaServerItem = mediaServerService.getOne(ssrcTransaction.getMediaServerId());
mediaServerService.releaseSsrc(mediaServerItem, ssrcTransaction.getSsrc());
streamSession.remove(deviceId, channelId);
}
} catch (SipException | ParseException e) {
e.printStackTrace();
}
@ -664,7 +743,7 @@ public class SIPCommander implements ISIPCommander {
broadcastXml.append("<Notify>\r\n");
broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
broadcastXml.append("<SourceID>" + sipConfig.getSipId() + "</SourceID>\r\n");
broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
broadcastXml.append("</Notify>\r\n");
@ -689,7 +768,7 @@ public class SIPCommander implements ISIPCommander {
broadcastXml.append("<Notify>\r\n");
broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
broadcastXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
broadcastXml.append("<SourceID>" + sipConfig.getSipId() + "</SourceID>\r\n");
broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
broadcastXml.append("</Notify>\r\n");
@ -721,7 +800,7 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@ -821,16 +900,16 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
cmdXml.append("<Info>\r\n");
}
if (!XmlUtil.isEmpty(alarmMethod)) {
if (!StringUtils.isEmpty(alarmMethod)) {
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
}
if (!XmlUtil.isEmpty(alarmType)) {
if (!StringUtils.isEmpty(alarmType)) {
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
}
if (!XmlUtil.isEmpty(alarmMethod) || !XmlUtil.isEmpty(alarmType)) {
if (!StringUtils.isEmpty(alarmMethod) || !StringUtils.isEmpty(alarmType)) {
cmdXml.append("</Info>\r\n");
}
cmdXml.append("</Control>\r\n");
@ -863,7 +942,7 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@ -901,7 +980,7 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@ -969,13 +1048,13 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
}
cmdXml.append("<BasicParam>\r\n");
if (!XmlUtil.isEmpty(name)) {
if (!StringUtils.isEmpty(name)) {
cmdXml.append("<Name>" + name + "</Name>\r\n");
}
if (NumericUtil.isInteger(expiration)) {
@ -1169,22 +1248,22 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
if (!XmlUtil.isEmpty(startPriority)) {
if (!StringUtils.isEmpty(startPriority)) {
cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
}
if (!XmlUtil.isEmpty(endPriority)) {
if (!StringUtils.isEmpty(endPriority)) {
cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
}
if (!XmlUtil.isEmpty(alarmMethod)) {
if (!StringUtils.isEmpty(alarmMethod)) {
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
}
if (!XmlUtil.isEmpty(alarmType)) {
if (!StringUtils.isEmpty(alarmType)) {
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
}
if (!XmlUtil.isEmpty(startTime)) {
if (!StringUtils.isEmpty(startTime)) {
cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
}
if (!XmlUtil.isEmpty(endTime)) {
if (!StringUtils.isEmpty(endTime)) {
cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
}
cmdXml.append("</Query>\r\n");
@ -1218,7 +1297,7 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@ -1253,7 +1332,7 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
if (XmlUtil.isEmpty(channelId)) {
if (StringUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
@ -1365,22 +1444,22 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
if (!XmlUtil.isEmpty(startPriority)) {
if (!StringUtils.isEmpty(startPriority)) {
cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
}
if (!XmlUtil.isEmpty(endPriority)) {
if (!StringUtils.isEmpty(endPriority)) {
cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
}
if (!XmlUtil.isEmpty(alarmMethod)) {
if (!StringUtils.isEmpty(alarmMethod)) {
cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
}
if (!XmlUtil.isEmpty(alarmType)) {
if (!StringUtils.isEmpty(alarmType)) {
cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
}
if (!XmlUtil.isEmpty(startTime)) {
if (!StringUtils.isEmpty(startTime)) {
cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
}
if (!XmlUtil.isEmpty(endTime)) {
if (!StringUtils.isEmpty(endTime)) {
cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
}
cmdXml.append("</Query>\r\n");
@ -1401,6 +1480,33 @@ public class SIPCommander implements ISIPCommander {
}
}
@Override
public boolean catalogSubscribe(Device device, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) {
try {
StringBuffer cmdXml = new StringBuffer(200);
cmdXml.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\r\n");
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>CataLog</CmdType>\r\n");
cmdXml.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
cmdXml.append("</Query>\r\n");
String tm = Long.toString(System.currentTimeMillis());
CallIdHeader callIdHeader = device.getTransport().equals("TCP") ? tcpSipProvider.getNewCallId()
: udpSipProvider.getNewCallId();
Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), "z9hG4bK-viaPos-" + tm, "fromTagPos" + tm, null, device.getSubscribeCycleForCatalog(), "presence" , callIdHeader);
transmitRequest(device, request, errorEvent, okEvent);
return true;
} catch ( NumberFormatException | ParseException | InvalidArgumentException | SipException e) {
e.printStackTrace();
return false;
}
}
private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
return transmitRequest(device, request, null, null);
@ -1421,26 +1527,20 @@ public class SIPCommander implements ISIPCommander {
CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
// 添加错误订阅
if (errorEvent != null) {
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), errorEvent);
sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
errorEvent.response(eventResult);
sipSubscribe.removeErrorSubscribe(eventResult.callId);
}));
}
// 添加订阅
if (okEvent != null) {
sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
okEvent.response(eventResult);
sipSubscribe.removeOkSubscribe(eventResult.callId);
});
}
clientTransaction.sendRequest();
return clientTransaction;
}
@Override
public void closeRTPServer(Device device, String channelId) {
if (mediaConfig.isRtpEnable()) {
String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
zlmrtpServerFactory.closeRTPServer(streamId);
}
streamSession.remove(device.getDeviceId(), channelId);
}
}

8
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java

@ -100,7 +100,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
if (event != null) {
logger.info("向上级平台 [ {} ] 注册发上错误: {} ",
parentPlatform.getServerGBId(),
event.getResponse().getReasonPhrase());
event.msg);
}
if (errorEvent != null ) {
errorEvent.response(event);
@ -263,10 +263,10 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform {
deviceInfoXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
deviceInfoXml.append("<SN>" +sn + "</SN>\r\n");
deviceInfoXml.append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n");
deviceInfoXml.append("<DeviceName>WVP-GB28181</DeviceName>\r\n");
deviceInfoXml.append("<Manufacturer>WVP</Manufacturer>\r\n");
deviceInfoXml.append("<DeviceName>" + parentPlatform.getName() + "</DeviceName>\r\n");
deviceInfoXml.append("<Manufacturer>wvp</Manufacturer>\r\n");
deviceInfoXml.append("<Model>wvp-28181-2.0</Model>\r\n");
deviceInfoXml.append("<Firmware>2.0.202103</Firmware>\r\n");
deviceInfoXml.append("<Firmware>2.0.202107</Firmware>\r\n");
deviceInfoXml.append("<Result>OK</Result>\r\n");
deviceInfoXml.append("</Response>\r\n");

14
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java

@ -0,0 +1,14 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import javax.sip.RequestEvent;
/**
* @description: 对SIP事件进行处理包括request response timeout ioException, transactionTerminated,dialogTerminated
* @author: panlinlin
* @date: 2021年11月5日 1547
*/
public interface ISIPRequestProcessor {
void process(RequestEvent event);
}

23
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorAbstract.java

@ -0,0 +1,23 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import gov.nist.javax.sip.SipProviderImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* @description:处理接收IPCamera发来的SIP协议请求消息
* @author: songww
* @date: 2020年5月3日 下午4:42:22
*/
public abstract class SIPRequestProcessorAbstract {
@Autowired
@Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider;
@Autowired
@Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider;
}

178
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java

@ -0,0 +1,178 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request;
import gov.nist.javax.sip.SipProviderImpl;
import gov.nist.javax.sip.SipStackImpl;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.stack.SIPServerTransaction;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.sip.*;
import javax.sip.address.Address;
import javax.sip.address.AddressFactory;
import javax.sip.address.SipURI;
import javax.sip.header.ContentTypeHeader;
import javax.sip.header.HeaderFactory;
import javax.sip.header.ViaHeader;
import javax.sip.message.MessageFactory;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
/**
* @description:处理接收IPCamera发来的SIP协议请求消息
* @author: songww
* @date: 2020年5月3日 下午4:42:22
*/
public abstract class SIPRequestProcessorParent {
private final static Logger logger = LoggerFactory.getLogger(SIPRequestProcessorParent.class);
@Autowired
@Qualifier(value="tcpSipProvider")
private SipProviderImpl tcpSipProvider;
@Autowired
@Qualifier(value="udpSipProvider")
private SipProviderImpl udpSipProvider;
/**
* 根据 RequestEvent 获取 ServerTransaction
* @param evt
* @return
*/
public ServerTransaction getServerTransaction(RequestEvent evt) {
Request request = evt.getRequest();
ServerTransaction serverTransaction = evt.getServerTransaction();
// 判断TCP还是UDP
boolean isTcp = false;
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String transport = reqViaHeader.getTransport();
if (transport.equals("TCP")) {
isTcp = true;
}
if (serverTransaction == null) {
try {
if (isTcp) {
SipStackImpl stack = (SipStackImpl)tcpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = tcpSipProvider.getNewServerTransaction(request);
}
} else {
SipStackImpl stack = (SipStackImpl)udpSipProvider.getSipStack();
serverTransaction = (SIPServerTransaction) stack.findTransaction((SIPRequest)request, true);
if (serverTransaction == null) {
serverTransaction = udpSipProvider.getNewServerTransaction(request);
}
}
} catch (TransactionAlreadyExistsException e) {
logger.error(e.getMessage());
} catch (TransactionUnavailableException e) {
logger.error(e.getMessage());
}
}
return serverTransaction;
}
public AddressFactory getAddressFactory() {
try {
return SipFactory.getInstance().createAddressFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public HeaderFactory getHeaderFactory() {
try {
return SipFactory.getInstance().createHeaderFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
public MessageFactory getMessageFactory() {
try {
return SipFactory.getInstance().createMessageFactory();
} catch (PeerUnavailableException e) {
e.printStackTrace();
}
return null;
}
/***
* 回复状态码
* 100 trying
* 200 OK
* 400
* 404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
public void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (statusCode >= 200) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
}
}
public void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
response.setReasonPhrase(msg);
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (statusCode >= 200) {
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
}
}
/**
* 回复带sdp的200
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
public void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public Element getRootElement(RequestEvent evt) throws DocumentException {
return getRootElement(evt, "gb2312");
}
public Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
if (charset == null) charset = "gb2312";
Request request = evt.getRequest();
SAXReader reader = new SAXReader();
reader.setEncoding(charset);
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
return xml.getRootElement();
}
}

251
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/AckRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/AckRequestProcessor.java

@ -1,126 +1,125 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.util.HashMap;
import java.util.Map;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:ACK请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:45
*/
public class AckRequestProcessor extends SIPRequestAbstractProcessor {
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
private IRedisCatchStorage redisCatchStorage;
private ZLMRTPServerFactory zlmrtpServerFactory;
/**
* 处理 ACK请求
*
* @param evt
*/
@Override
public void process(RequestEvent evt) {
//Request request = evt.getRequest();
Dialog dialog = evt.getDialog();
if (dialog == null) return;
//DialogState state = dialog.getState();
if (/*request.getMecodewwthod().equals(Request.INVITE) &&*/ dialog.getState()== DialogState.CONFIRMED) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
String deviceId = sendRtpItem.getDeviceId();
StreamInfo streamInfo = null;
if (deviceId == null) {
streamInfo = new StreamInfo();
streamInfo.setApp(sendRtpItem.getApp());
streamInfo.setStreamId(sendRtpItem.getStreamId());
}else {
streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
sendRtpItem.setStreamId(streamInfo.getStreamId());
streamInfo.setApp("rtp");
}
redisCatchStorage.updateSendRTPSever(sendRtpItem);
logger.info(platformGbId);
logger.info(channelId);
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app",streamInfo.getApp());
param.put("stream",streamInfo.getStreamId());
param.put("ssrc", sendRtpItem.getSsrc());
param.put("dst_url",sendRtpItem.getIp());
param.put("dst_port", sendRtpItem.getPort());
param.put("is_udp", is_Udp);
//param.put ("src_port", sendRtpItem.getLocalPort());
// 设备推流查询,成功后才能转推
boolean rtpPushed = false;
long startTime = System.currentTimeMillis();
while (!rtpPushed) {
try {
if (System.currentTimeMillis() - startTime < 30 * 1000) {
if (zlmrtpServerFactory.isStreamReady(streamInfo.getApp(), streamInfo.getStreamId())) {
rtpPushed = true;
logger.info("已获取设备推流,开始向上级推流");
zlmrtpServerFactory.startSendRtpStream(param);
} else {
logger.info("等待设备推流.......");
Thread.sleep(1000);
continue;
}
} else {
rtpPushed = true;
logger.info("设备推流超时,终止向上级推流");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// try {
// Request ackRequest = null;
// CSeq csReq = (CSeq) request.getHeader(CSeq.NAME);
// ackRequest = dialog.createAck(csReq.getSeqNumber());
// dialog.sendAck(ackRequest);
// logger.info("send ack to callee:" + ackRequest.toString());
// } catch (SipException e) {
// e.printStackTrace();
// } catch (InvalidArgumentException e) {
// e.printStackTrace();
// }
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.Dialog;
import javax.sip.DialogState;
import javax.sip.RequestEvent;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import java.util.HashMap;
import java.util.Map;
/**
* @description:ACK请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:45
*/
@Component
public class AckRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private Logger logger = LoggerFactory.getLogger(AckRequestProcessor.class);
private String method = "ACK";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private IMediaServerService mediaServerService;
/**
* 处理 ACK请求
*
* @param evt
*/
@Override
public void process(RequestEvent evt) {
Dialog dialog = evt.getDialog();
if (dialog == null) return;
if (dialog.getState()== DialogState.CONFIRMED) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
String is_Udp = sendRtpItem.isTcp() ? "0" : "1";
String deviceId = sendRtpItem.getDeviceId();
StreamInfo streamInfo = null;
if (deviceId == null) {
streamInfo = new StreamInfo();
streamInfo.setApp(sendRtpItem.getApp());
streamInfo.setStreamId(sendRtpItem.getStreamId());
}else {
streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
sendRtpItem.setStreamId(streamInfo.getStreamId());
streamInfo.setApp("rtp");
}
redisCatchStorage.updateSendRTPSever(sendRtpItem);
logger.info(platformGbId);
logger.info(channelId);
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app",streamInfo.getApp());
param.put("stream",streamInfo.getStreamId());
param.put("ssrc", sendRtpItem.getSsrc());
param.put("dst_url",sendRtpItem.getIp());
param.put("dst_port", sendRtpItem.getPort());
param.put("is_udp", is_Udp);
//param.put ("src_port", sendRtpItem.getLocalPort());
// 设备推流查询,成功后才能转推
boolean rtpPushed = false;
long startTime = System.currentTimeMillis();
while (!rtpPushed) {
try {
if (System.currentTimeMillis() - startTime < 30 * 1000) {
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
if (zlmrtpServerFactory.isStreamReady(mediaInfo, streamInfo.getApp(), streamInfo.getStreamId())) {
rtpPushed = true;
logger.info("已获取设备推流[{}/{}],开始向上级推流[{}:{}]",
streamInfo.getApp() ,streamInfo.getStreamId(), sendRtpItem.getIp(), sendRtpItem.getPort());
zlmrtpServerFactory.startSendRtpStream(mediaInfo, param);
} else {
logger.info("等待设备推流[{}/{}].......",
streamInfo.getApp() ,streamInfo.getStreamId());
Thread.sleep(1000);
continue;
}
} else {
rtpPushed = true;
logger.info("设备推流[{}/{}]超时,终止向上级推流",
streamInfo.getApp() ,streamInfo.getStreamId());
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}

117
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java

@ -0,0 +1,117 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.SendRtpItem;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.*;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;
/**
* @description: BYE请求处理器
* @author: lawrencehj
* @date: 2021年3月9日
*/
@Component
public class ByeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private Logger logger = LoggerFactory.getLogger(ByeRequestProcessor.class);
@Autowired
private ISIPCommander cmder;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private IMediaServerService mediaServerService;
private String method = "BYE";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 处理BYE请求
* @param evt
*/
@Override
public void process(RequestEvent evt) {
try {
responseAck(evt, Response.OK);
Dialog dialog = evt.getDialog();
if (dialog == null) return;
if (dialog.getState().equals(DialogState.TERMINATED)) {
String platformGbId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(FromHeader.NAME)).getAddress().getURI()).getUser();
String channelId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(platformGbId, channelId);
logger.info("收到bye, [{}/{}]", platformGbId, channelId);
if (sendRtpItem != null){
String streamId = sendRtpItem.getStreamId();
Map<String, Object> param = new HashMap<>();
param.put("vhost","__defaultVhost__");
param.put("app",sendRtpItem.getApp());
param.put("stream",streamId);
param.put("ssrc",sendRtpItem.getSsrc());
logger.info("停止向上级推流:" + streamId);
MediaServerItem mediaInfo = mediaServerService.getOne(sendRtpItem.getMediaServerId());
zlmrtpServerFactory.stopSendRtpStream(mediaInfo, param);
redisCatchStorage.deleteSendRTPServer(platformGbId, channelId);
if (zlmrtpServerFactory.totalReaderCount(mediaInfo, sendRtpItem.getApp(), streamId) == 0) {
logger.info(streamId + "无其它观看者,通知设备停止推流");
cmder.streamByeCmd(sendRtpItem.getDeviceId(), channelId);
}
}
// 可能是设备主动停止
Device device = storager.queryVideoDeviceByChannelId(platformGbId);
if (device != null) {
StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(device.getDeviceId(), channelId);
if (streamInfo != null) {
redisCatchStorage.stopPlay(streamInfo);
}
storager.stopPlay(device.getDeviceId(), channelId);
mediaServerService.closeRTPServer(device, channelId);
}
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

42
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java

@ -0,0 +1,42 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
/**
* @description:CANCEL请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:32:23
*/
@Component
public class CancelRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private String method = "CANCEL";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 处理CANCEL请求
*
* @param evt 事件
*/
@Override
public void process(RequestEvent evt) {
// TODO 优先级99 Cancel Request消息实现,此消息一般为级联消息,上级给下级发送请求取消指令
}
}

835
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/InviteRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java

@ -1,447 +1,388 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.SipFactory;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.media.zlm.ZLMServerConfig;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import com.genersoft.iot.vmp.service.IPlayService;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.ParseException;
import java.util.Vector;
/**
* @Description:处理INVITE请求
* @author: panll
* @date: 2021年1月14日
*/
@SuppressWarnings("rawtypes")
public class InviteRequestProcessor extends SIPRequestAbstractProcessor {
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private SIPCommanderFroPlatform cmderFroPlatform;
private IVideoManagerStorager storager;
private IRedisCatchStorage redisCatchStorage;
private SIPCommander cmder;
private IPlayService playService;
private ZLMRTPServerFactory zlmrtpServerFactory;
public ZLMRTPServerFactory getZlmrtpServerFactory() {
return zlmrtpServerFactory;
}
public void setZlmrtpServerFactory(ZLMRTPServerFactory zlmrtpServerFactory) {
this.zlmrtpServerFactory = zlmrtpServerFactory;
}
/**
* 处理invite请求
*
* @param evt
* 请求消息
*/
@Override
public void process(RequestEvent evt) {
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
try {
Request request = evt.getRequest();
SipURI sipURI = (SipURI) request.getRequestURI();
String channelId = sipURI.getUser();
String requesterId = null;
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
requesterId = uri.getUser();
if (requesterId == null || channelId == null) {
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
return;
}
// 查询请求方是否上级平台
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
if (platform != null) {
// 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
// 不是通道可能是直播流
if (channel != null && gbStream == null ) {
if (channel.getStatus() == 0) {
logger.info("通道离线,返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
return;
}
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else if(channel == null && gbStream != null){
Boolean streamReady = zlmrtpServerFactory.isStreamReady(gbStream.getApp(), gbStream.getStream());
if (!streamReady) {
logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
return;
}
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else {
logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
return;
}
// 解析sdp消息, 使用jainsip 自带的sdp解析方式
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
int ssrcIndex = contentString.indexOf("y=");
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String substring = contentString.substring(0, contentString.indexOf("y="));
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
//String ip = null;
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("96")) {
port = media.getMediaPort();
//String mediaType = media.getMediaType();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
}else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
//String sessionName = sdp.getSessionName().getValue();
logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
Device device = null;
// 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标
if (channel != null) {
device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
if (device == null) {
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
responseAck(evt, Response.SERVER_INTERNAL_ERROR);
return;
}
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
device.getDeviceId(), channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 通知下级推流,
PlayResult playResult = playService.play(device.getDeviceId(), channelId, (responseJSON)->{
// 收到推流, 回复200OK, 等待ack
// if (sendRtpItem == null) return;
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("t=0 0\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
} ,(event -> {
// 未知错误。直接转发设备点播的错误
Response response = null;
try {
response = getMessageFactory().createResponse(event.getResponse().getStatusCode(), evt.getRequest());
getServerTransaction(evt).sendResponse(response);
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}));
if (logger.isDebugEnabled()) {
logger.debug(playResult.getResult().toString());
}
}else if (gbStream != null) {
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(addressStr, port, ssrc, requesterId,
gbStream.getApp(), gbStream.getStream(), channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
ZLMServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaInfo.getSdpIp()+"\r\n");
content.append("t=0 0\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
} else {
// 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
Device device = storager.queryVideoDevice(requesterId);
if (device != null) {
logger.info("收到设备" + requesterId + "的语音广播Invite请求");
responseAck(evt, Response.TRYING);
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
String substring = contentString;
String ssrc = "0000000404";
int ssrcIndex = contentString.indexOf("y=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
}
ssrcIndex = substring.indexOf("f=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
}
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("8")) {
port = media.getMediaPort();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
} else {
logger.warn("来自无效设备/平台的请求");
responseAck(evt, Response.BAD_REQUEST);
}
}
} catch (SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
logger.warn("sdp解析错误");
e.printStackTrace();
} catch (SdpParseException e) {
e.printStackTrace();
} catch (SdpException e) {
e.printStackTrace();
}
}
/***
* 回复状态码
* 100 trying
* 200 OK
* 400
* 404
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, int statusCode) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
private void responseAck(RequestEvent evt, int statusCode, String msg) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(statusCode, evt.getRequest());
response.setReasonPhrase(msg);
getServerTransaction(evt).sendResponse(response);
}
/**
* 回复带sdp的200
* @param evt
* @param sdp
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void responseAck(RequestEvent evt, String sdp) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
SipFactory sipFactory = SipFactory.getInstance();
ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
response.setContent(sdp, contentTypeHeader);
SipURI sipURI = (SipURI)evt.getRequest().getRequestURI();
Address concatAddress = sipFactory.createAddressFactory().createAddress(
sipFactory.createAddressFactory().createSipURI(sipURI.getUser(), sipURI.getHost()+":"+sipURI.getPort()
));
response.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
getServerTransaction(evt).sendResponse(response);
}
public SIPCommanderFroPlatform getCmderFroPlatform() {
return cmderFroPlatform;
}
public void setCmderFroPlatform(SIPCommanderFroPlatform cmderFroPlatform) {
this.cmderFroPlatform = cmderFroPlatform;
}
public IVideoManagerStorager getStorager() {
return storager;
}
public void setStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
public SIPCommander getCmder() {
return cmder;
}
public void setCmder(SIPCommander cmder) {
this.cmder = cmder;
}
public IPlayService getPlayService() {
return playService;
}
public void setPlayService(IPlayService playService) {
this.playService = playService;
}
public IRedisCatchStorage getRedisCatchStorage() {
return redisCatchStorage;
}
public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
this.redisCatchStorage = redisCatchStorage;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
import com.genersoft.iot.vmp.service.IMediaServerService;
import com.genersoft.iot.vmp.service.IPlayService;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.play.bean.PlayResult;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sdp.*;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.address.SipURI;
import javax.sip.header.FromHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Vector;
/**
* @description:处理INVITE请求
* @author: panll
* @date: 2021年1月14日
*/
@SuppressWarnings("rawtypes")
@Component
public class InviteRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private final static Logger logger = LoggerFactory.getLogger(InviteRequestProcessor.class);
private String method = "INVITE";
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private SIPCommander cmder;
@Autowired
private IPlayService playService;
@Autowired
private ZLMRTPServerFactory zlmrtpServerFactory;
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 处理invite请求
*
* @param evt
* 请求消息
*/
@Override
public void process(RequestEvent evt) {
// Invite Request消息实现,此消息一般为级联消息,上级给下级发送请求视频指令
try {
Request request = evt.getRequest();
SipURI sipURI = (SipURI) request.getRequestURI();
String channelId = sipURI.getUser();
String requesterId = null;
FromHeader fromHeader = (FromHeader)request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
requesterId = uri.getUser();
if (requesterId == null || channelId == null) {
logger.info("无法从FromHeader的Address中获取到平台id,返回400");
responseAck(evt, Response.BAD_REQUEST); // 参数不全, 发400,请求错误
return;
}
// 查询请求方是否上级平台
ParentPlatform platform = storager.queryParentPlatByServerGBId(requesterId);
if (platform != null) {
// 查询平台下是否有该通道
DeviceChannel channel = storager.queryChannelInParentPlatform(requesterId, channelId);
GbStream gbStream = storager.queryStreamInParentPlatform(requesterId, channelId);
MediaServerItem mediaServerItem = null;
// 不是通道可能是直播流
if (channel != null && gbStream == null ) {
if (channel.getStatus() == 0) {
logger.info("通道离线,返回400");
responseAck(evt, Response.BAD_REQUEST, "channel [" + channel.getChannelId() + "] offline");
return;
}
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else if(channel == null && gbStream != null){
String mediaServerId = gbStream.getMediaServerId();
mediaServerItem = mediaServerService.getOne(mediaServerId);
if (mediaServerItem == null) {
logger.info("[ app={}, stream={} ]找不到zlm {},返回410",gbStream.getApp(), gbStream.getStream(), mediaServerId);
responseAck(evt, Response.GONE, "media server not found");
return;
}
Boolean streamReady = zlmrtpServerFactory.isStreamReady(mediaServerItem, gbStream.getApp(), gbStream.getStream());
if (!streamReady ) {
logger.info("[ app={}, stream={} ]通道离线,返回400",gbStream.getApp(), gbStream.getStream());
responseAck(evt, Response.BAD_REQUEST, "channel [" + gbStream.getGbId() + "] offline");
return;
}
responseAck(evt, Response.CALL_IS_BEING_FORWARDED); // 通道存在,发181,呼叫转接中
}else {
logger.info("通道不存在,返回404");
responseAck(evt, Response.NOT_FOUND); // 通道不存在,发404,资源不存在
return;
}
// 解析sdp消息, 使用jainsip 自带的sdp解析方式
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
int ssrcIndex = contentString.indexOf("y=");
//ssrc规定长度为10字节,不取余下长度以避免后续还有“f=”字段
String ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
String substring = contentString.substring(0, contentString.indexOf("y="));
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
//String ip = null;
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (Object description : mediaDescriptions) {
MediaDescription mediaDescription = (MediaDescription) description;
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("96")) {
port = media.getMediaPort();
//String mediaType = media.getMediaType();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
//String sessionName = sdp.getSessionName().getValue();
logger.info("[上级点播]用户:{}, 地址:{}:{}, ssrc:{}", username, addressStr, port, ssrc);
Device device = null;
// 通过 channel 和 gbStream 是否为null 值判断来源是直播流合适国标
if (channel != null) {
device = storager.queryVideoDeviceByPlatformIdAndChannelId(requesterId, channelId);
if (device == null) {
logger.warn("点播平台{}的通道{}时未找到设备信息", requesterId, channel);
responseAck(evt, Response.SERVER_INTERNAL_ERROR);
return;
}
mediaServerItem = playService.getNewMediaServerItem(device);
if (mediaServerItem == null) {
logger.warn("未找到可用的zlm");
responseAck(evt, Response.BUSY_HERE);
return;
}
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
device.getDeviceId(), channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// 通知下级推流,
PlayResult playResult = playService.play(mediaServerItem,device.getDeviceId(), channelId, (mediaServerItemInUSe, responseJSON)->{
// 收到推流, 回复200OK, 等待ack
// if (sendRtpItem == null) return;
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaServerItemInUSe.getSdpIp()+"\r\n");
content.append("t=0 0\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
} ,((event) -> {
// 未知错误。直接转发设备点播的错误
Response response = null;
try {
response = getMessageFactory().createResponse(event.statusCode, evt.getRequest());
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}));
if (logger.isDebugEnabled()) {
logger.debug(playResult.getResult().toString());
}
}else if (gbStream != null) {
SendRtpItem sendRtpItem = zlmrtpServerFactory.createSendRtpItem(mediaServerItem, addressStr, port, ssrc, requesterId,
gbStream.getApp(), gbStream.getStream(), channelId,
mediaTransmissionTCP);
if (tcpActive != null) {
sendRtpItem.setTcpActive(tcpActive);
}
if (sendRtpItem == null) {
logger.warn("服务器端口资源不足");
responseAck(evt, Response.BUSY_HERE);
return;
}
// 写入redis, 超时时回复
redisCatchStorage.updateSendRTPSever(sendRtpItem);
sendRtpItem.setStatus(1);
redisCatchStorage.updateSendRTPSever(sendRtpItem);
// TODO 添加对tcp的支持
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o="+ channelId +" 0 0 IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
content.append("s=Play\r\n");
content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
content.append("t=0 0\r\n");
content.append("m=video "+ sendRtpItem.getLocalPort()+" RTP/AVP 96\r\n");
content.append("a=sendonly\r\n");
content.append("a=rtpmap:96 PS/90000\r\n");
content.append("y="+ ssrc + "\r\n");
content.append("f=\r\n");
try {
responseAck(evt, content.toString());
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
} else {
// 非上级平台请求,查询是否设备请求(通常为接收语音广播的设备)
Device device = storager.queryVideoDevice(requesterId);
if (device != null) {
logger.info("收到设备" + requesterId + "的语音广播Invite请求");
responseAck(evt, Response.TRYING);
String contentString = new String(request.getRawContent());
// jainSip不支持y=字段, 移除移除以解析。
String substring = contentString;
String ssrc = "0000000404";
int ssrcIndex = contentString.indexOf("y=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
ssrc = contentString.substring(ssrcIndex + 2, ssrcIndex + 12);
}
ssrcIndex = substring.indexOf("f=");
if (ssrcIndex > 0) {
substring = contentString.substring(0, ssrcIndex);
}
SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring);
// 获取支持的格式
Vector mediaDescriptions = sdp.getMediaDescriptions(true);
// 查看是否支持PS 负载96
int port = -1;
//boolean recvonly = false;
boolean mediaTransmissionTCP = false;
Boolean tcpActive = null;
for (int i = 0; i < mediaDescriptions.size(); i++) {
MediaDescription mediaDescription = (MediaDescription)mediaDescriptions.get(i);
Media media = mediaDescription.getMedia();
Vector mediaFormats = media.getMediaFormats(false);
if (mediaFormats.contains("8")) {
port = media.getMediaPort();
String protocol = media.getProtocol();
// 区分TCP发流还是udp, 当前默认udp
if ("TCP/RTP/AVP".equals(protocol)) {
String setup = mediaDescription.getAttribute("setup");
if (setup != null) {
mediaTransmissionTCP = true;
if ("active".equals(setup)) {
tcpActive = true;
} else if ("passive".equals(setup)) {
tcpActive = false;
}
}
}
break;
}
}
if (port == -1) {
logger.info("不支持的媒体格式,返回415");
// 回复不支持的格式
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE); // 不支持的格式,发415
return;
}
String username = sdp.getOrigin().getUsername();
String addressStr = sdp.getOrigin().getAddress();
logger.info("设备{}请求语音流,地址:{}:{},ssrc:{}", username, addressStr, port, ssrc);
} else {
logger.warn("来自无效设备/平台的请求");
responseAck(evt, Response.BAD_REQUEST);
}
}
} catch (SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
logger.warn("sdp解析错误");
e.printStackTrace();
} catch (SdpParseException e) {
e.printStackTrace();
} catch (SdpException e) {
e.printStackTrace();
}
}
}

2146
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/MessageRequestProcessor1.java

File diff suppressed because it is too large

108
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/NotifyRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java

@ -1,66 +1,78 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.io.ByteArrayInputStream;
import java.text.ParseException;
import java.util.Iterator;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Request;
import javax.sip.message.Response;
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Iterator;
/**
* @Description: Notify请求处理器
* @description: Notify请求处理器
* @author: lawrencehj
* @date: 2021年1月27日
*/
@Component
public class NotifyRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
private UserSetup userSetup = (UserSetup) SpringBeanFactory.getBean("userSetup");
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private final static Logger logger = LoggerFactory.getLogger(NotifyRequestProcessor.class);
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Autowired
private EventPublisher publisher;
@Autowired
private DeviceOffLineDetector offLineDetector;
private static final String NOTIFY_CATALOG = "Catalog";
private static final String NOTIFY_ALARM = "Alarm";
private static final String NOTIFY_MOBILE_POSITION = "MobilePosition";
private String method = "NOTIFY";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
@Override
public void process(RequestEvent evt) {
@ -79,7 +91,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
processNotifyMobilePosition(evt);
} else {
logger.info("接收到消息:" + cmd);
response200Ok(evt);
responseAck(evt, Response.OK);
}
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
@ -134,7 +146,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
storager.clearMobilePositionsByDeviceId(deviceId);
}
storager.insertMobilePosition(mobilePosition);
response200Ok(evt);
responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
@ -155,6 +167,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
if (device == null) {
return;
}
rootElement = getRootElement(evt, device.getCharset());
DeviceAlarm deviceAlarm = new DeviceAlarm();
deviceAlarm.setDeviceId(deviceId);
deviceAlarm.setAlarmPriority(XmlUtil.getText(rootElement, "AlarmPriority"));
@ -197,7 +210,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// TODO: 需要实现存储报警信息、报警分类
// 回复200 OK
response200Ok(evt);
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(deviceId)) {
publisher.deviceAlarmEventPublish(deviceAlarm);
}
@ -213,19 +226,26 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
*/
private void processNotifyCatalogList(RequestEvent evt) {
try {
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
String deviceId = SipUtils.getUserIdFromFromHeader(fromHeader);
Element rootElement = getRootElement(evt);
Element deviceIdElement = rootElement.element("DeviceID");
String deviceId = deviceIdElement.getText();
String channelId = deviceIdElement.getText();
Device device = storager.queryVideoDevice(deviceId);
if (device == null) {
return;
}
if (device != null ) {
rootElement = getRootElement(evt, device.getCharset());
}
Element deviceListElement = rootElement.element("DeviceList");
if (deviceListElement == null) {
return;
}
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) {
if (device == null) {
return;
}
// 遍历DeviceList
while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next();
@ -322,7 +342,7 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
// msg.setData(device);
// deferredResultHolder.invokeResult(msg);
// 回复200 OK
response200Ok(evt);
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(deviceId)) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
}
@ -332,26 +352,8 @@ public class NotifyRequestProcessor extends SIPRequestAbstractProcessor {
}
}
/***
* 回复200 OK
*
* @param evt
* @throws SipException
* @throws InvalidArgumentException
* @throws ParseException
*/
private void response200Ok(RequestEvent evt) throws SipException, InvalidArgumentException, ParseException {
Response response = getMessageFactory().createResponse(Response.OK, evt.getRequest());
getServerTransaction(evt).sendResponse(response);
}
private Element getRootElement(RequestEvent evt) throws DocumentException {
Request request = evt.getRequest();
SAXReader reader = new SAXReader();
reader.setEncoding("gbk");
Document xml = reader.read(new ByteArrayInputStream(request.getRawContent()));
return xml.getRootElement();
}
public void setCmder(SIPCommander cmder) {
}

396
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java

@ -1,197 +1,199 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Locale;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.AuthorizationHeader;
import javax.sip.header.ContactHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.FromHeader;
import javax.sip.header.ViaHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
import gov.nist.javax.sip.RequestEventExt;
import gov.nist.javax.sip.header.SIPDateHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires;
/**
* @Description:收到注册请求 处理
* @author: swwheihei
* @date: 2020年5月3日 下午4:47:25
*/
public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
private SipConfig sipConfig;
private RegisterLogicHandler handler;
private IVideoManagerStorager storager;
private EventPublisher publisher;
/**
* 收到注册请求 处理
* @param evt
*/
@Override
public void process(RequestEvent evt) {
try {
RequestEventExt evtExt = (RequestEventExt)evt;
String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
logger.info("[{}] 收到注册请求,开始处理", requestAddress);
Request request = evt.getRequest();
Response response = null;
boolean passwordCorrect = false;
// 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功
int registerFlag = 0;
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
String deviceId = uri.getUser();
Device device = storager.queryVideoDevice(deviceId);
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
// 校验密码是否正确
if (authorhead != null) {
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
sipConfig.getSipPassword());
}
if (StringUtils.isEmpty(sipConfig.getSipPassword())){
passwordCorrect = true;
}
// 未携带授权头或者密码错误 回复401
if (authorhead == null ) {
if (authorhead == null) {
logger.info("[{}] 未携带授权头 回复401", requestAddress);
} else if (!passwordCorrect) {
logger.info("[{}] 密码错误 回复401", requestAddress);
}
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getSipDomain());
}else {
if (!passwordCorrect){
// 注册失败
response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
response.setReasonPhrase("wrong password");
}else {
// 携带授权头并且密码正确
response = getMessageFactory().createResponse(Response.OK, request);
// 添加date头
SIPDateHeader dateHeader = new SIPDateHeader();
// 使用自己修改的
WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
dateHeader.setDate(wvpSipDate);
response.addHeader(dateHeader);
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
if (expiresHeader == null) {
response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
getServerTransaction(evt).sendResponse(response);
return;
}
// 添加Contact头
response.addHeader(request.getHeader(ContactHeader.NAME));
// 添加Expires头
response.addHeader(request.getExpires());
// 获取到通信地址等信息
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String received = viaHeader.getReceived();
int rPort = viaHeader.getRPort();
// 解析本地地址替代
if (StringUtils.isEmpty(received) || rPort == -1) {
received = viaHeader.getHost();
rPort = viaHeader.getPort();
}
//
if (device == null) {
device = new Device();
device.setStreamMode("UDP");
device.setDeviceId(deviceId);
}
device.setIp(received);
device.setPort(rPort);
device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
// 注销成功
if (expiresHeader.getExpires() == 0) {
registerFlag = 2;
}
// 注册成功
else {
device.setExpires(expiresHeader.getExpires());
registerFlag = 1;
// 判断TCP还是UDP
boolean isTcp = false;
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String transport = reqViaHeader.getTransport();
if (transport.equals("TCP")) {
isTcp = true;
}
device.setTransport(isTcp ? "TCP" : "UDP");
}
}
}
getServerTransaction(evt).sendResponse(response);
// 注册成功
// 保存到redis
// 下发catelog查询目录
if (registerFlag == 1 ) {
logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER);
// 重新注册更新设备和通道,以免设备替换或更新后信息无法更新
handler.onRegister(device);
} else if (registerFlag == 2) {
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
}
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
e.printStackTrace();
}
}
public void setSipConfig(SipConfig sipConfig) {
this.sipConfig = sipConfig;
}
public void setHandler(RegisterLogicHandler handler) {
this.handler = handler;
}
public void setVideoManagerStorager(IVideoManagerStorager storager) {
this.storager = storager;
}
public void setPublisher(EventPublisher publisher) {
this.publisher = publisher;
}
}
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
import com.genersoft.iot.vmp.gb28181.auth.RegisterLogicHandler;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import gov.nist.javax.sip.RequestEventExt;
import gov.nist.javax.sip.address.AddressImpl;
import gov.nist.javax.sip.address.SipUri;
import gov.nist.javax.sip.header.Expires;
import gov.nist.javax.sip.header.SIPDateHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.header.*;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Locale;
/**
* @description:收到注册请求 处理
* @author: swwheihei
* @date: 2020年5月3日 下午4:47:25
*/
@Component
public class RegisterRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private Logger logger = LoggerFactory.getLogger(RegisterRequestProcessor.class);
public String method = "REGISTER";
@Autowired
private SipConfig sipConfig;
@Autowired
private RegisterLogicHandler handler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private EventPublisher publisher;
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 收到注册请求 处理
* @param evt
*/
@Override
public void process(RequestEvent evt) {
try {
RequestEventExt evtExt = (RequestEventExt)evt;
String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
logger.info("[{}] 收到注册请求,开始处理", requestAddress);
Request request = evt.getRequest();
Response response = null;
boolean passwordCorrect = false;
// 注册标志 0:未携带授权头或者密码错误 1:注册成功 2:注销成功
int registerFlag = 0;
FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
AddressImpl address = (AddressImpl) fromHeader.getAddress();
SipUri uri = (SipUri) address.getURI();
String deviceId = uri.getUser();
Device device = storager.queryVideoDevice(deviceId);
AuthorizationHeader authorhead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
// 校验密码是否正确
if (authorhead != null) {
passwordCorrect = new DigestServerAuthenticationHelper().doAuthenticatePlainTextPassword(request,
sipConfig.getPassword());
}
if (StringUtils.isEmpty(sipConfig.getPassword())){
passwordCorrect = true;
}
// 未携带授权头或者密码错误 回复401
if (authorhead == null ) {
logger.info("[{}] 未携带授权头 回复401", requestAddress);
response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
}else {
if (!passwordCorrect){
// 注册失败
response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
response.setReasonPhrase("wrong password");
logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress);
}else {
// 携带授权头并且密码正确
response = getMessageFactory().createResponse(Response.OK, request);
// 添加date头
SIPDateHeader dateHeader = new SIPDateHeader();
// 使用自己修改的
WvpSipDate wvpSipDate = new WvpSipDate(Calendar.getInstance(Locale.ENGLISH).getTimeInMillis());
dateHeader.setDate(wvpSipDate);
response.addHeader(dateHeader);
ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
if (expiresHeader == null) {
response = getMessageFactory().createResponse(Response.BAD_REQUEST, request);
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
return;
}
// 添加Contact头
response.addHeader(request.getHeader(ContactHeader.NAME));
// 添加Expires头
response.addHeader(request.getExpires());
// 获取到通信地址等信息
ViaHeader viaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String received = viaHeader.getReceived();
int rPort = viaHeader.getRPort();
// 解析本地地址替代
if (StringUtils.isEmpty(received) || rPort == -1) {
received = viaHeader.getHost();
rPort = viaHeader.getPort();
}
//
if (device == null) {
device = new Device();
device.setStreamMode("UDP");
device.setCharset("gb2312");
device.setDeviceId(deviceId);
device.setFirsRegister(true);
}
device.setIp(received);
device.setPort(rPort);
device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
// 注销成功
if (expiresHeader.getExpires() == 0) {
registerFlag = 2;
}
// 注册成功
else {
device.setExpires(expiresHeader.getExpires());
registerFlag = 1;
// 判断TCP还是UDP
boolean isTcp = false;
ViaHeader reqViaHeader = (ViaHeader) request.getHeader(ViaHeader.NAME);
String transport = reqViaHeader.getTransport();
if (transport.equals("TCP")) {
isTcp = true;
}
device.setTransport(isTcp ? "TCP" : "UDP");
}
}
}
ServerTransaction serverTransaction = getServerTransaction(evt);
serverTransaction.sendResponse(response);
if (serverTransaction.getDialog() != null) serverTransaction.getDialog().delete();
// 注册成功
// 保存到redis
// 下发catelog查询目录
if (registerFlag == 1 ) {
logger.info("[{}] 注册成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_REGISTER);
// 重新注册更新设备和通道,以免设备替换或更新后信息无法更新
handler.onRegister(device);
} else if (registerFlag == 2) {
logger.info("[{}] 注销成功! deviceId:" + device.getDeviceId(), requestAddress);
publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
}
} catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
e.printStackTrace();
}
}
}

141
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/SubscribeRequestProcessor.java → src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java

@ -1,64 +1,77 @@
package com.genersoft.iot.vmp.gb28181.transmit.request.impl;
import java.text.ParseException;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.header.ExpiresHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import com.genersoft.iot.vmp.gb28181.transmit.request.SIPRequestAbstractProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @Description:SUBSCRIBE请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:20
*/
public class SubscribeRequestProcessor extends SIPRequestAbstractProcessor {
private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
/**
* 处理SUBSCRIBE请求
*
* @param evt
* @param layer
* @param transaction
* @param config
*/
@Override
public void process(RequestEvent evt) {
Request request = evt.getRequest();
try {
Response response = null;
response = getMessageFactory().createResponse(200, request);
if (response != null) {
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
response.setExpires(expireHeader);
}
logger.info("response : " + response.toString());
ServerTransaction transaction = getServerTransaction(evt);
if (transaction != null) {
transaction.sendResponse(response);
transaction.terminate();
} else {
logger.info("processRequest serverTransactionId is null.");
}
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
}
}
}
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.ServerTransaction;
import javax.sip.SipException;
import javax.sip.header.ExpiresHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;
import java.text.ParseException;
/**
* @description:SUBSCRIBE请求处理器
* @author: swwheihei
* @date: 2020年5月3日 下午5:31:20
*/
@Component
public class SubscribeRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private Logger logger = LoggerFactory.getLogger(SubscribeRequestProcessor.class);
private String method = "SUBSCRIBE";
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
/**
* 处理SUBSCRIBE请求
*
* @param evt
*/
@Override
public void process(RequestEvent evt) {
Request request = evt.getRequest();
try {
Response response = null;
response = getMessageFactory().createResponse(200, request);
if (response != null) {
ExpiresHeader expireHeader = getHeaderFactory().createExpiresHeader(30);
response.setExpires(expireHeader);
}
logger.info("response : " + response.toString());
ServerTransaction transaction = getServerTransaction(evt);
if (transaction != null) {
transaction.sendResponse(response);
transaction.getDialog().delete();
transaction.terminate();
} else {
logger.info("processRequest serverTransactionId is null.");
}
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
}
}
}

23
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java

@ -0,0 +1,23 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import org.dom4j.Element;
import javax.sip.RequestEvent;
public interface IMessageHandler {
/**
* 处理来自设备的信息
* @param evt
* @param device
*/
void handForDevice(RequestEvent evt, Device device, Element element);
/**
* 处理来自平台的信息
* @param evt
* @param parentPlatform
*/
void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element);
}

43
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java

@ -0,0 +1,43 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import javax.sip.RequestEvent;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent implements IMessageHandler{
public static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
@Autowired
public MessageRequestProcessor messageRequestProcessor;
public void addHandler(String cmdType, IMessageHandler messageHandler) {
messageHandlerMap.put(cmdType, messageHandler);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String cmd = getText(element, "CmdType");
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
if (messageHandler != null) {
messageHandler.handForDevice(evt, device, element);
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
String cmd = getText(element, "CmdType");
IMessageHandler messageHandler = messageHandlerMap.get(cmd);
if (messageHandler != null) {
messageHandler.handForPlatform(evt, parentPlatform, element);
}
}
}

91
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java

@ -0,0 +1,91 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class MessageRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
private final static Logger logger = LoggerFactory.getLogger(MessageRequestProcessor.class);
private final String method = "MESSAGE";
private static Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
@Autowired
private SIPProcessorObserver sipProcessorObserver;
@Autowired
private IVideoManagerStorager storage;
@Override
public void afterPropertiesSet() throws Exception {
// 添加消息处理的订阅
sipProcessorObserver.addRequestProcessor(method, this);
}
public void addHandler(String name, IMessageHandler handler) {
messageHandlerMap.put(name, handler);
}
@Override
public void process(RequestEvent evt) {
logger.debug("接收到消息:" + evt.getRequest());
String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest());
// 查询设备是否存在
Device device = storage.queryVideoDevice(deviceId);
// 查询上级平台是否存在
ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
try {
if (device == null && parentPlatform == null) {
// 不存在则回复404
responseAck(evt, Response.NOT_FOUND, "device id not found");
}else {
Element rootElement = getRootElement(evt);
String name = rootElement.getName();
IMessageHandler messageHandler = messageHandlerMap.get(name);
if (messageHandler != null) {
if (device != null) {
messageHandler.handForDevice(evt, device, rootElement);
}else { // 由于上面已经判断都为null则直接返回,所以这里device和parentPlatform必有一个不为null
messageHandler.handForPlatform(evt, parentPlatform, rootElement);
}
}else {
// 不支持的message
// 不存在则回复415
responseAck(evt, Response.UNSUPPORTED_MEDIA_TYPE, "Unsupported message type, must Control/Notify/Query/Response");
}
}
} catch (SipException e) {
logger.warn("SIP 回复错误", e);
} catch (InvalidArgumentException e) {
logger.warn("参数无效", e);
} catch (ParseException e) {
logger.warn("SIP回复时解析异常", e);
} catch (DocumentException e) {
logger.warn("解析XML消息内容异常", e);
}
}
}

21
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java

@ -0,0 +1,21 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ControlMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Control";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

16
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java

@ -0,0 +1,16 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class NotifyMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Notify";
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

114
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java

@ -0,0 +1,114 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.*;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.service.IDeviceAlarmService;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(AlarmNotifyMessageHandler.class);
private final String cmdType = "Alarm";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private EventPublisher publisher;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private IDeviceAlarmService deviceAlarmService;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getText().toString();
DeviceAlarm deviceAlarm = new DeviceAlarm();
deviceAlarm.setDeviceId(device.getDeviceId());
deviceAlarm.setChannelId(channelId);
deviceAlarm.setAlarmPriority(getText(rootElement, "AlarmPriority"));
deviceAlarm.setAlarmMethod(getText(rootElement, "AlarmMethod"));
deviceAlarm.setAlarmTime(getText(rootElement, "AlarmTime"));
if (getText(rootElement, "AlarmDescription") == null) {
deviceAlarm.setAlarmDescription("");
} else {
deviceAlarm.setAlarmDescription(getText(rootElement, "AlarmDescription"));
}
if (NumericUtil.isDouble(getText(rootElement, "Longitude"))) {
deviceAlarm.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
} else {
deviceAlarm.setLongitude(0.00);
}
if (NumericUtil.isDouble(getText(rootElement, "Latitude"))) {
deviceAlarm.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
} else {
deviceAlarm.setLatitude(0.00);
}
if (!StringUtils.isEmpty(deviceAlarm.getAlarmMethod())) {
if ( deviceAlarm.getAlarmMethod().equals("4")) {
MobilePosition mobilePosition = new MobilePosition();
mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
mobilePosition.setTime(deviceAlarm.getAlarmTime());
mobilePosition.setLongitude(deviceAlarm.getLongitude());
mobilePosition.setLatitude(deviceAlarm.getLatitude());
mobilePosition.setReportSource("GPS Alarm");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
}
}
logger.debug("存储报警信息、报警分类");
// 存储报警信息、报警分类
deviceAlarmService.add(deviceAlarm);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.deviceAlarmEventPublish(deviceAlarm);
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

120
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/CatalogNotifyMessageHandler.java

@ -0,0 +1,120 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class CatalogNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogNotifyMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId();
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
// 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size();
// 回复级联的通道
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
// 回复直播的通道
if (gbStreams.size() > 0) {
for (GbStream gbStream : gbStreams) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannel.setName(gbStream.getName());
deviceChannel.setLongitude(gbStream.getLongitude());
deviceChannel.setLatitude(gbStream.getLatitude());
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0);
deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
if (size == 0) {
// 回复无通道
cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

63
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java

@ -0,0 +1,63 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(KeepaliveNotifyMessageHandler.class);
private final String cmdType = "Keepalive";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
// 检查设备是否存在并在线, 不在线则设置为在线
try {
if (device != null ) {
// 回复200 OK
responseAck(evt, Response.OK);
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
// 不会收到上级平台的心跳信息
}
}

74
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java

@ -0,0 +1,74 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.common.StreamInfo;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MediaStatusNotifyMessageHandler.class);
private final String cmdType = "MediaStatus";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private SIPCommander cmder;
@Autowired
private IRedisCatchStorage redisCatchStorage;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String NotifyType =getText(rootElement, "NotifyType");
if (NotifyType.equals("121")){
logger.info("媒体播放完毕,通知关流");
StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(device.getDeviceId(), "*");
if (streamInfo != null) {
redisCatchStorage.stopPlayback(streamInfo);
cmder.streamByeCmd(streamInfo.getDeviceID(), streamInfo.getChannelId());
}
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

103
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MobilePositionNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MobilePositionNotifyMessageHandler.class);
private final String cmdType = "MobilePosition";
@Autowired
private NotifyMessageHandler notifyMessageHandler;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Override
public void afterPropertiesSet() throws Exception {
notifyMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
rootElement = getRootElement(evt, device.getCharset());
MobilePosition mobilePosition = new MobilePosition();
if (!StringUtils.isEmpty(device.getName())) {
mobilePosition.setDeviceName(device.getName());
}
mobilePosition.setDeviceId(device.getDeviceId());
mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
mobilePosition.setTime(getText(rootElement, "Time"));
mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed")));
} else {
mobilePosition.setSpeed(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Direction"))) {
mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction")));
} else {
mobilePosition.setDirection(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) {
mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude")));
} else {
mobilePosition.setAltitude(0.0);
}
mobilePosition.setReportSource("Mobile Position");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
//回复 200 OK
responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

21
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java

@ -0,0 +1,21 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class QueryMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Query";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

120
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java

@ -0,0 +1,120 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.GbStream;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.List;
@Component
public class CatalogQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogQueryMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + parentPlatform.getServerGBId();
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
Element snElement = rootElement.element("SN");
String sn = snElement.getText();
// 准备回复通道信息
List<ChannelReduce> channelReduces = storager.queryChannelListInParentPlatform(parentPlatform.getServerGBId());
// 查询关联的直播通道
List<GbStream> gbStreams = storager.queryGbStreamListInPlatform(parentPlatform.getServerGBId());
int size = channelReduces.size() + gbStreams.size();
// 回复级联的通道
if (channelReduces.size() > 0) {
for (ChannelReduce channelReduce : channelReduces) {
DeviceChannel deviceChannel = storager.queryChannel(channelReduce.getDeviceId(), channelReduce.getChannelId());
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
// 回复直播的通道
if (gbStreams.size() > 0) {
for (GbStream gbStream : gbStreams) {
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setChannelId(gbStream.getGbId());
deviceChannel.setName(gbStream.getName());
deviceChannel.setLongitude(gbStream.getLongitude());
deviceChannel.setLatitude(gbStream.getLatitude());
deviceChannel.setDeviceId(parentPlatform.getDeviceGBId());
deviceChannel.setManufacture("wvp-pro");
deviceChannel.setStatus(gbStream.isStatus()?1:0);
// deviceChannel.setParentId(parentPlatform.getDeviceGBId());
deviceChannel.setRegisterWay(1);
deviceChannel.setCivilCode(config.getDomain());
deviceChannel.setModel("live");
deviceChannel.setOwner("wvp-pro");
deviceChannel.setParental(0);
deviceChannel.setSecrecy("0");
deviceChannel.setSecrecy("0");
cmderFroPlatform.catalogQuery(deviceChannel, parentPlatform, sn, fromHeader.getTag(), size);
}
}
if (size == 0) {
// 回复无通道
cmderFroPlatform.catalogQuery(null, parentPlatform, sn, fromHeader.getTag(), size);
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}

111
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceControlQueryMessageHandler.java

@ -0,0 +1,111 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.VManageBootstrap;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.SpringBeanFactory;
import gov.nist.javax.sip.SipStackImpl;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.ListeningPoint;
import javax.sip.ObjectInUseException;
import javax.sip.RequestEvent;
import javax.sip.SipProvider;
import javax.sip.address.SipURI;
import javax.sip.header.HeaderAddress;
import javax.sip.header.ToHeader;
import java.util.Iterator;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceControlQueryMessageHandler.class);
private final String cmdType = "DeviceControl";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommander cmder;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
// 此处是上级发出的DeviceControl指令
String targetGBId = ((SipURI) ((HeaderAddress) evt.getRequest().getHeader(ToHeader.NAME)).getAddress().getURI()).getUser();
String channelId = getText(rootElement, "DeviceID");
// 远程启动功能
if (!StringUtils.isEmpty(getText(rootElement, "TeleBoot"))) {
if (parentPlatform.getServerGBId().equals(targetGBId)) {
// 远程启动本平台:需要在重新启动程序后先对SipStack解绑
logger.info("执行远程启动本平台命令");
cmderFroPlatform.unregister(parentPlatform, null, null);
Thread restartThread = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(3000);
SipProvider up = (SipProvider) SpringBeanFactory.getBean("udpSipProvider");
SipStackImpl stack = (SipStackImpl)up.getSipStack();
stack.stop();
Iterator listener = stack.getListeningPoints();
while (listener.hasNext()) {
stack.deleteListeningPoint((ListeningPoint) listener.next());
}
Iterator providers = stack.getSipProviders();
while (providers.hasNext()) {
stack.deleteSipProvider((SipProvider) providers.next());
}
VManageBootstrap.restart();
} catch (InterruptedException ignored) {
} catch (ObjectInUseException e) {
e.printStackTrace();
}
}
});
restartThread.setDaemon(false);
restartThread.start();
} else {
// 远程启动指定设备
}
}
// 云台/前端控制命令
if (!StringUtils.isEmpty(getText(rootElement,"PTZCmd")) && !parentPlatform.getServerGBId().equals(targetGBId)) {
String cmdString = getText(rootElement,"PTZCmd");
Device deviceForPlatform = storager.queryVideoDeviceByPlatformIdAndChannelId(parentPlatform.getServerGBId(), channelId);
cmder.fronEndCmd(deviceForPlatform, channelId, cmdString);
}
}
}

62
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java

@ -0,0 +1,62 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceInfoQueryMessageHandler.class);
private final String cmdType = "DeviceInfo";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
logger.info("接收到DeviceInfo查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
try {
// 回复200 OK
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String sn = rootElement.element("SN").getText();
cmderFroPlatform.deviceInfoResponse(parentPlatform, sn, fromHeader.getTag());
}
}

75
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java

@ -0,0 +1,75 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.QueryMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.header.FromHeader;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceStatusQueryMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceStatusQueryMessageHandler.class);
private final String cmdType = "DeviceStatus";
@Autowired
private QueryMessageHandler queryMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private SIPCommanderFroPlatform cmderFroPlatform;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
queryMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
logger.info("接收到DeviceStatus查询消息");
FromHeader fromHeader = (FromHeader) evt.getRequest().getHeader(FromHeader.NAME);
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
String sn = rootElement.element("SN").getText();
cmderFroPlatform.deviceStatusResponse(parentPlatform, sn, fromHeader.getTag());
}
}

21
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java

@ -0,0 +1,21 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ResponseMessageHandler extends MessageHandlerAbstract implements InitializingBean {
private final String messageType = "Response";
@Autowired
private MessageRequestProcessor messageRequestProcessor;
@Override
public void afterPropertiesSet() throws Exception {
messageRequestProcessor.addHandler(messageType, this);
}
}

58
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java

@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
@Component
public class AlarmResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(AlarmResponseMessageHandler.class);
private final String cmdType = "Alarm";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getText().toString();
String key = DeferredResultHolder.CALLBACK_CMD_ALARM + device.getDeviceId() + channelId;
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

72
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java

@ -0,0 +1,72 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class BroadcastResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(BroadcastResponseMessageHandler.class);
private final String cmdType = "Broadcast";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
String channelId = getText(rootElement, "DeviceID");
String key = DeferredResultHolder.CALLBACK_CMD_BROADCAST + device.getDeviceId() + channelId;
// 回复200 OK
responseAck(evt, Response.OK);
// 此处是对本平台发出Broadcast指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(rootElement, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} catch (ParseException | SipException | InvalidArgumentException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

182
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java

@ -0,0 +1,182 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.Iterator;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class CatalogResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(CatalogResponseMessageHandler.class);
private final String cmdType = "Catalog";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String key = DeferredResultHolder.CALLBACK_CMD_CATALOG + device.getDeviceId();
Element rootElement = null;
try {
rootElement = getRootElement(evt, device.getCharset());
Element deviceListElement = rootElement.element("DeviceList");
Iterator<Element> deviceListIterator = deviceListElement.elementIterator();
if (deviceListIterator != null) {
// 遍历DeviceList
while (deviceListIterator.hasNext()) {
Element itemDevice = deviceListIterator.next();
Element channelDeviceElement = itemDevice.element("DeviceID");
if (channelDeviceElement == null) {
continue;
}
String channelDeviceId = channelDeviceElement.getText();
Element channdelNameElement = itemDevice.element("Name");
String channelName = channdelNameElement != null ? channdelNameElement.getTextTrim().toString() : "";
Element statusElement = itemDevice.element("Status");
String status = statusElement != null ? statusElement.getText().toString() : "ON";
DeviceChannel deviceChannel = new DeviceChannel();
deviceChannel.setName(channelName);
deviceChannel.setChannelId(channelDeviceId);
// ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
if (status.equals("ON") || status.equals("On") || status.equals("ONLINE")) {
deviceChannel.setStatus(1);
}
if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
deviceChannel.setStatus(0);
}
deviceChannel.setManufacture(getText(itemDevice, "Manufacturer"));
deviceChannel.setModel(getText(itemDevice, "Model"));
deviceChannel.setOwner(getText(itemDevice, "Owner"));
deviceChannel.setCivilCode(getText(itemDevice, "CivilCode"));
deviceChannel.setBlock(getText(itemDevice, "Block"));
deviceChannel.setAddress(getText(itemDevice, "Address"));
if (getText(itemDevice, "Parental") == null || getText(itemDevice, "Parental") == "") {
deviceChannel.setParental(0);
} else {
deviceChannel.setParental(Integer.parseInt(getText(itemDevice, "Parental")));
}
deviceChannel.setParentId(getText(itemDevice, "ParentID"));
if (getText(itemDevice, "SafetyWay") == null || getText(itemDevice, "SafetyWay") == "") {
deviceChannel.setSafetyWay(0);
} else {
deviceChannel.setSafetyWay(Integer.parseInt(getText(itemDevice, "SafetyWay")));
}
if (getText(itemDevice, "RegisterWay") == null || getText(itemDevice, "RegisterWay") == "") {
deviceChannel.setRegisterWay(1);
} else {
deviceChannel.setRegisterWay(Integer.parseInt(getText(itemDevice, "RegisterWay")));
}
deviceChannel.setCertNum(getText(itemDevice, "CertNum"));
if (getText(itemDevice, "Certifiable") == null || getText(itemDevice, "Certifiable") == "") {
deviceChannel.setCertifiable(0);
} else {
deviceChannel.setCertifiable(Integer.parseInt(getText(itemDevice, "Certifiable")));
}
if (getText(itemDevice, "ErrCode") == null || getText(itemDevice, "ErrCode") == "") {
deviceChannel.setErrCode(0);
} else {
deviceChannel.setErrCode(Integer.parseInt(getText(itemDevice, "ErrCode")));
}
deviceChannel.setEndTime(getText(itemDevice, "EndTime"));
deviceChannel.setSecrecy(getText(itemDevice, "Secrecy"));
deviceChannel.setIpAddress(getText(itemDevice, "IPAddress"));
if (getText(itemDevice, "Port") == null || getText(itemDevice, "Port") == "") {
deviceChannel.setPort(0);
} else {
deviceChannel.setPort(Integer.parseInt(getText(itemDevice, "Port")));
}
deviceChannel.setPassword(getText(itemDevice, "Password"));
if (NumericUtil.isDouble(getText(itemDevice, "Longitude"))) {
deviceChannel.setLongitude(Double.parseDouble(getText(itemDevice, "Longitude")));
} else {
deviceChannel.setLongitude(0.00);
}
if (NumericUtil.isDouble(getText(itemDevice, "Latitude"))) {
deviceChannel.setLatitude(Double.parseDouble(getText(itemDevice, "Latitude")));
} else {
deviceChannel.setLatitude(0.00);
}
if (getText(itemDevice, "PTZType") == null || getText(itemDevice, "PTZType") == "") {
deviceChannel.setPTZType(0);
} else {
deviceChannel.setPTZType(Integer.parseInt(getText(itemDevice, "PTZType")));
}
deviceChannel.setHasAudio(true); // 默认含有音频,播放时再检查是否有音频及是否AAC
storager.updateChannel(device.getDeviceId(), deviceChannel);
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(device);
deferredResultHolder.invokeAllResult(msg);
// 回复200 OK
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
}
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

81
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java

@ -0,0 +1,81 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(ConfigDownloadResponseMessageHandler.class);
private final String cmdType = "ConfigDownload";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private EventPublisher publisher;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
String channelId = getText(element, "DeviceID");
String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId;
try {
// 回复200 OK
responseAck(evt, Response.OK);
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
// 不会收到上级平台的心跳信息
}
}

58
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java

@ -0,0 +1,58 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceConfigResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceConfigResponseMessageHandler.class);
private final String cmdType = "DeviceConfig";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
String channelId = getText(element, "DeviceID");
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + device.getDeviceId() + channelId;
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

59
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java

@ -0,0 +1,59 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.RequestEvent;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceControlResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceControlResponseMessageHandler.class);
private final String cmdType = "DeviceControl";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
// 此处是对本平台发出DeviceControl指令的应答
JSONObject json = new JSONObject();
String channelId = getText(element, "DeviceID");
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId;
msg.setKey(key);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

103
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.conf.SipConfig;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceInfoResponseMessageHandler.class);
private final String cmdType = "DeviceInfo";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private IVideoManagerStorager storager;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private SipConfig config;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
logger.debug("接收到DeviceInfo应答消息");
try {
rootElement = getRootElement(evt, device.getCharset());
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getTextTrim();
String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + device.getDeviceId() + channelId;
device.setName(getText(rootElement, "DeviceName"));
device.setManufacturer(getText(rootElement, "Manufacturer"));
device.setModel(getText(rootElement, "Model"));
device.setFirmware(getText(rootElement, "Firmware"));
if (StringUtils.isEmpty(device.getStreamMode())) {
device.setStreamMode("UDP");
}
storager.updateDevice(device);
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(device);
deferredResultHolder.invokeAllResult(msg);
// 回复200 OK
responseAck(evt, Response.OK);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (SipException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

89
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java

@ -0,0 +1,89 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.alibaba.fastjson.JSONObject;
import com.genersoft.iot.vmp.common.VideoManagerConstants;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.XmlUtil;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
@Component
public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(DeviceStatusResponseMessageHandler.class);
private final String cmdType = "DeviceStatus";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private DeviceOffLineDetector offLineDetector;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private EventPublisher publisher;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element element) {
logger.info("接收到DeviceStatus应答消息");
// 检查设备是否存在, 不存在则不回复
// 回复200 OK
try {
responseAck(evt, Response.OK);
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
Element deviceIdElement = element.element("DeviceID");
String channelId = deviceIdElement.getText();
JSONObject json = new JSONObject();
XmlUtil.node2Json(element, json);
if (logger.isDebugEnabled()) {
logger.debug(json.toJSONString());
}
RequestMessage msg = new RequestMessage();
msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId() + channelId);
msg.setData(json);
deferredResultHolder.invokeAllResult(msg);
if (offLineDetector.isOnline(device.getDeviceId())) {
publisher.onlineEventPublish(device, VideoManagerConstants.EVENT_ONLINE_MESSAGE);
} else {
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element rootElement) {
}
}

103
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java

@ -0,0 +1,103 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.conf.UserSetup;
import com.genersoft.iot.vmp.gb28181.bean.BaiduPoint;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.MobilePosition;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
import com.genersoft.iot.vmp.utils.GpsUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class MobilePositionResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(MobilePositionResponseMessageHandler.class);
private final String cmdType = "MobilePosition";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private UserSetup userSetup;
@Autowired
private IVideoManagerStorager storager;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
try {
rootElement = getRootElement(evt, device.getCharset());
MobilePosition mobilePosition = new MobilePosition();
if (!StringUtils.isEmpty(device.getName())) {
mobilePosition.setDeviceName(device.getName());
}
mobilePosition.setDeviceId(device.getDeviceId());
mobilePosition.setChannelId(getText(rootElement, "DeviceID"));
mobilePosition.setTime(getText(rootElement, "Time"));
mobilePosition.setLongitude(Double.parseDouble(getText(rootElement, "Longitude")));
mobilePosition.setLatitude(Double.parseDouble(getText(rootElement, "Latitude")));
if (NumericUtil.isDouble(getText(rootElement, "Speed"))) {
mobilePosition.setSpeed(Double.parseDouble(getText(rootElement, "Speed")));
} else {
mobilePosition.setSpeed(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Direction"))) {
mobilePosition.setDirection(Double.parseDouble(getText(rootElement, "Direction")));
} else {
mobilePosition.setDirection(0.0);
}
if (NumericUtil.isDouble(getText(rootElement, "Altitude"))) {
mobilePosition.setAltitude(Double.parseDouble(getText(rootElement, "Altitude")));
} else {
mobilePosition.setAltitude(0.0);
}
mobilePosition.setReportSource("Mobile Position");
BaiduPoint bp = new BaiduPoint();
bp = GpsUtil.Wgs84ToBd09(String.valueOf(mobilePosition.getLongitude()), String.valueOf(mobilePosition.getLatitude()));
logger.info("百度坐标:" + bp.getBdLng() + ", " + bp.getBdLat());
mobilePosition.setGeodeticSystem("BD-09");
mobilePosition.setCnLng(bp.getBdLng());
mobilePosition.setCnLat(bp.getBdLat());
if (!userSetup.getSavePositionHistory()) {
storager.clearMobilePositionsByDeviceId(device.getDeviceId());
}
storager.insertMobilePosition(mobilePosition);
//回复 200 OK
responseAck(evt, Response.OK);
} catch (DocumentException | SipException | InvalidArgumentException | ParseException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

153
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java

@ -0,0 +1,153 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd;
import com.genersoft.iot.vmp.gb28181.bean.Device;
import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread;
import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
import com.genersoft.iot.vmp.utils.redis.RedisUtil;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.sip.InvalidArgumentException;
import javax.sip.RequestEvent;
import javax.sip.SipException;
import javax.sip.message.Response;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;
import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
@Component
public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
private Logger logger = LoggerFactory.getLogger(RecordInfoResponseMessageHandler.class);
public static volatile List<String> threadNameList = new ArrayList();
private final String cmdType = "RecordInfo";
private final static String CACHE_RECORDINFO_KEY = "CACHE_RECORDINFO_";
@Autowired
private ResponseMessageHandler responseMessageHandler;
@Autowired
private RedisUtil redis;
@Autowired
private DeferredResultHolder deferredResultHolder;
@Override
public void afterPropertiesSet() throws Exception {
responseMessageHandler.addHandler(cmdType, this);
}
@Override
public void handForDevice(RequestEvent evt, Device device, Element rootElement) {
// 回复200 OK
try {
responseAck(evt, Response.OK);
rootElement = getRootElement(evt, device.getCharset());
String uuid = UUID.randomUUID().toString().replace("-", "");
RecordInfo recordInfo = new RecordInfo();
Element deviceIdElement = rootElement.element("DeviceID");
String channelId = deviceIdElement.getText();
String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + channelId;
recordInfo.setDeviceId(device.getDeviceId());
recordInfo.setChannelId(channelId);
recordInfo.setName(getText(rootElement, "Name"));
if (getText(rootElement, "SumNum") == null || getText(rootElement, "SumNum") == "") {
recordInfo.setSumNum(0);
} else {
recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum")));
}
String sn = getText(rootElement, "SN");
Element recordListElement = rootElement.element("RecordList");
if (recordListElement == null || recordInfo.getSumNum() == 0) {
logger.info("无录像数据");
RequestMessage msg = new RequestMessage();
msg.setKey(key);
msg.setData(recordInfo);
deferredResultHolder.invokeAllResult(msg);
} else {
Iterator<Element> recordListIterator = recordListElement.elementIterator();
List<RecordItem> recordList = new ArrayList<RecordItem>();
if (recordListIterator != null) {
RecordItem record = new RecordItem();
logger.info("处理录像列表数据...");
// 遍历DeviceList
while (recordListIterator.hasNext()) {
Element itemRecord = recordListIterator.next();
Element recordElement = itemRecord.element("DeviceID");
if (recordElement == null) {
logger.info("记录为空,下一个...");
continue;
}
record = new RecordItem();
record.setDeviceId(getText(itemRecord, "DeviceID"));
record.setName(getText(itemRecord, "Name"));
record.setFilePath(getText(itemRecord, "FilePath"));
record.setAddress(getText(itemRecord, "Address"));
record.setStartTime(
DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime")));
record.setEndTime(
DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "EndTime")));
record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
: Integer.parseInt(getText(itemRecord, "Secrecy")));
record.setType(getText(itemRecord, "Type"));
record.setRecorderId(getText(itemRecord, "RecorderID"));
recordList.add(record);
}
recordInfo.setRecordList(recordList);
}
// 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题
String cacheKey = CACHE_RECORDINFO_KEY + device.getDeviceId() + sn;
redis.set(cacheKey + "_" + uuid, recordList, 90);
if (!threadNameList.contains(cacheKey)) {
threadNameList.add(cacheKey);
CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo);
chk.setName(cacheKey);
chk.setDeferredResultHolder(deferredResultHolder);
chk.setRedis(redis);
chk.setLogger(logger);
chk.start();
if (logger.isDebugEnabled()) {
logger.debug("Start Thread " + cacheKey + ".");
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("Thread " + cacheKey + " already started.");
}
}
}
} catch (SipException e) {
e.printStackTrace();
} catch (InvalidArgumentException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
@Override
public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
}
}

15
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java

@ -0,0 +1,15 @@
package com.genersoft.iot.vmp.gb28181.transmit.event.response;
import javax.sip.ResponseEvent;
/**
* @description:处理接收IPCamera发来的SIP协议响应消息
* @author: swwheihei
* @date: 2020年5月3日 下午4:42:22
*/
public interface ISIPResponseProcessor {
void process(ResponseEvent evt);
}

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save