Commit 88350873ee7632924cb135a450fef9f4d05c5306

Authored by 648540858
2 parents d9cfe061 f57ed350

Merge branch 'wvp-28181-2.0' into main-dev

# Conflicts:
#	src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java
#	src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
Showing 365 changed files with 3884 additions and 2745 deletions
doc/_content/introduction/config.md
... ... @@ -153,7 +153,7 @@ user-settings:
153 153 # 国标是否录制
154 154 record-sip: true
155 155 # 是否将日志存储进数据库
156   - logInDatebase: true
  156 + logInDatabase: true
157 157 # 第三方匹配,用于从stream钟获取有效信息
158 158 thirdPartyGBIdReg: [\s\S]*
159 159 ```
... ...
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
1   -package com.genersoft.iot.vmp;
2   -
3   -import com.genersoft.iot.vmp.utils.GitUtil;
4   -import com.genersoft.iot.vmp.utils.SpringBeanFactory;
5   -import org.slf4j.Logger;
6   -import org.slf4j.LoggerFactory;
7   -import org.springframework.boot.SpringApplication;
8   -import org.springframework.boot.autoconfigure.SpringBootApplication;
9   -import org.springframework.boot.builder.SpringApplicationBuilder;
10   -import org.springframework.boot.web.servlet.ServletComponentScan;
11   -import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
12   -import org.springframework.context.ConfigurableApplicationContext;
13   -import org.springframework.scheduling.annotation.EnableScheduling;
14   -
15   -import javax.servlet.ServletContext;
16   -import javax.servlet.ServletException;
17   -import javax.servlet.SessionCookieConfig;
18   -import javax.servlet.SessionTrackingMode;
19   -import java.util.Collections;
20   -
21   -/**
22   - * 启动类
23   - */
24   -@ServletComponentScan("com.genersoft.iot.vmp.conf")
25   -@SpringBootApplication
26   -@EnableScheduling
27   -public class VManageBootstrap extends SpringBootServletInitializer {
28   -
29   - private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
30   -
31   - private static String[] args;
32   - private static ConfigurableApplicationContext context;
33   - public static void main(String[] args) {
34   - VManageBootstrap.args = args;
35   - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
36   - GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil");
37   - logger.info("构建版本: {}", gitUtil1.getBuildVersion());
38   - logger.info("构建时间: {}", gitUtil1.getBuildDate());
39   - logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime());
40   - }
41   - // 项目重启
42   - public static void restart() {
43   - context.close();
44   - VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
45   - }
46   -
47   - @Override
48   - protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
49   - return application.sources(VManageBootstrap.class);
50   - }
51   -
52   - @Override
53   - public void onStartup(ServletContext servletContext) throws ServletException {
54   - super.onStartup(servletContext);
55   -
56   - servletContext.setSessionTrackingModes(
57   - Collections.singleton(SessionTrackingMode.COOKIE)
58   - );
59   - SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
60   - sessionCookieConfig.setHttpOnly(true);
61   -
62   - }
63   -}
  1 +package com.genersoft.iot.vmp;
  2 +
  3 +import com.genersoft.iot.vmp.utils.GitUtil;
  4 +import com.genersoft.iot.vmp.utils.SpringBeanFactory;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.boot.SpringApplication;
  8 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  9 +import org.springframework.boot.builder.SpringApplicationBuilder;
  10 +import org.springframework.boot.web.servlet.ServletComponentScan;
  11 +import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
  12 +import org.springframework.context.ConfigurableApplicationContext;
  13 +import org.springframework.scheduling.annotation.EnableScheduling;
  14 +
  15 +import javax.servlet.ServletContext;
  16 +import javax.servlet.ServletException;
  17 +import javax.servlet.SessionCookieConfig;
  18 +import javax.servlet.SessionTrackingMode;
  19 +import java.util.Collections;
  20 +
  21 +/**
  22 + * 启动类
  23 + */
  24 +@ServletComponentScan("com.genersoft.iot.vmp.conf")
  25 +@SpringBootApplication
  26 +@EnableScheduling
  27 +public class VManageBootstrap extends SpringBootServletInitializer {
  28 +
  29 + private final static Logger logger = LoggerFactory.getLogger(VManageBootstrap.class);
  30 +
  31 + private static String[] args;
  32 + private static ConfigurableApplicationContext context;
  33 + public static void main(String[] args) {
  34 + VManageBootstrap.args = args;
  35 + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
  36 + GitUtil gitUtil1 = SpringBeanFactory.getBean("gitUtil");
  37 + logger.info("构建版本: {}", gitUtil1.getBuildVersion());
  38 + logger.info("构建时间: {}", gitUtil1.getBuildDate());
  39 + logger.info("GIT最后提交时间: {}", gitUtil1.getCommitTime());
  40 + }
  41 + // 项目重启
  42 + public static void restart() {
  43 + context.close();
  44 + VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args);
  45 + }
  46 +
  47 + @Override
  48 + protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
  49 + return application.sources(VManageBootstrap.class);
  50 + }
  51 +
  52 + @Override
  53 + public void onStartup(ServletContext servletContext) throws ServletException {
  54 + super.onStartup(servletContext);
  55 +
  56 + servletContext.setSessionTrackingModes(
  57 + Collections.singleton(SessionTrackingMode.COOKIE)
  58 + );
  59 + SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig();
  60 + sessionCookieConfig.setHttpOnly(true);
  61 +
  62 + }
  63 +}
... ...
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
1   -package com.genersoft.iot.vmp.common;
2   -
3   -/**
4   - * @description: 定义常量
5   - * @author: swwheihei
6   - * @date: 2019年5月30日 下午3:04:04
7   - *
8   - */
9   -public class VideoManagerConstants {
10   -
11   - public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_";
12   -
13   - public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_";
14   -
15   - public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
16   -
17   - public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
18   -
19   - public static final String DEVICE_PREFIX = "VMP_DEVICE_";
20   -
21   - // 设备同步完成
22   - public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_";
23   -
24   - public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
25   -
26   - public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_";
27   -
28   - // TODO 此处多了一个_,暂不修改
29   - public static final String INVITE_PREFIX = "VMP_INVITE";
30   - public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_";
31   - public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_";
32   - public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_";
33   -
34   - public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_";
35   -
36   - public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
37   -
38   - public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
39   -
40   - public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
41   -
42   - public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
43   -
44   - public static final String EVENT_ONLINE_REGISTER = "1";
45   -
46   - public static final String EVENT_ONLINE_MESSAGE = "3";
47   -
48   - public static final String EVENT_OUTLINE_UNREGISTER = "1";
49   -
50   - public static final String EVENT_OUTLINE_TIMEOUT = "2";
51   -
52   - public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_";
53   -
54   - public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
55   -
56   - public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_";
57   -
58   - public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
59   -
60   - public static final String SIP_SN_PREFIX = "VMP_SIP_SN_";
61   -
62   - public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_";
63   -
64   - public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_";
65   -
66   - public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_";
67   -
68   - public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
69   -
70   - public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
71   - public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_";
72   -
73   - public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
74   -
75   -
76   -
77   -
78   - //************************** redis 消息*********************************
79   -
80   - /**
81   - * 流变化的通知
82   - */
83   - public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
84   -
85   - /**
86   - * 接收推流设备的GPS变化通知
87   - */
88   - public static final String VM_MSG_GPS = "VM_MSG_GPS";
89   -
90   - /**
91   - * 接收推流设备的GPS变化通知
92   - */
93   - public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE";
94   - /**
95   - * 接收推流设备列表更新变化通知
96   - */
97   - public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE";
98   -
99   - /**
100   - * redis 消息通知设备推流到平台
101   - */
102   - public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED";
103   -
104   - /**
105   - * redis 消息通知上级平台开始观看流
106   - */
107   - public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY";
108   -
109   - /**
110   - * redis 消息通知上级平台停止观看流
111   - */
112   - public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY";
113   -
114   - /**
115   - * redis 消息接收关闭一个推流
116   - */
117   - public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED";
118   -
119   -
120   - /**
121   - * redis 消息通知平台通知设备推流结果
122   - */
123   - public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
124   -
125   - /**
126   - * redis 通知平台关闭推流
127   - */
128   - public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
129   -
130   - /**
131   - * redis 消息请求所有的在线通道
132   - */
133   - public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
134   -
135   - /**
136   - * 移动位置订阅通知
137   - */
138   - public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition";
139   -
140   - /**
141   - * 报警订阅的通知(收到报警向redis发出通知)
142   - */
143   - public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm";
144   -
145   -
146   - /**
147   - * 报警通知的发送 (收到redis发出的通知,转发给其他平台)
148   - */
149   - public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive";
150   -
151   - /**
152   - * 设备状态订阅的通知
153   - */
154   - public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device";
155   -
156   -
157   - //************************** 第三方 ****************************************
158   -
159   - public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
160   - public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
161   - public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_";
162   - public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_";
163   -
164   - /**
165   - * Redis Const
166   - * 设备录像信息结果前缀
167   - */
168   - public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";
169   - /**
170   - * Redis Const
171   - * 设备录像信息结果前缀
172   - */
173   - public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
174   -
175   -}
  1 +package com.genersoft.iot.vmp.common;
  2 +
  3 +/**
  4 + * @description: 定义常量
  5 + * @author: swwheihei
  6 + * @date: 2019年5月30日 下午3:04:04
  7 + *
  8 + */
  9 +public class VideoManagerConstants {
  10 +
  11 + public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_";
  12 +
  13 + public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_";
  14 +
  15 + public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_";
  16 +
  17 + public static final String MEDIA_SERVERS_ONLINE_PREFIX = "VMP_MEDIA_ONLINE_SERVERS_";
  18 +
  19 + public static final String DEVICE_PREFIX = "VMP_DEVICE_";
  20 +
  21 + // 设备同步完成
  22 + public static final String DEVICE_SYNC_PREFIX = "VMP_DEVICE_SYNC_";
  23 +
  24 + public static final String CACHEKEY_PREFIX = "VMP_CHANNEL_";
  25 +
  26 + public static final String KEEPLIVEKEY_PREFIX = "VMP_KEEPALIVE_";
  27 +
  28 + // TODO 此处多了一个_,暂不修改
  29 + public static final String INVITE_PREFIX = "VMP_INVITE";
  30 + public static final String PLAYER_PREFIX = "VMP_INVITE_PLAY_";
  31 + public static final String PLAY_BLACK_PREFIX = "VMP_INVITE_PLAYBACK_";
  32 + public static final String DOWNLOAD_PREFIX = "VMP_INVITE_DOWNLOAD_";
  33 +
  34 + public static final String PLATFORM_KEEPALIVE_PREFIX = "VMP_PLATFORM_KEEPALIVE_";
  35 +
  36 + public static final String PLATFORM_CATCH_PREFIX = "VMP_PLATFORM_CATCH_";
  37 +
  38 + public static final String PLATFORM_REGISTER_PREFIX = "VMP_PLATFORM_REGISTER_";
  39 +
  40 + public static final String PLATFORM_REGISTER_INFO_PREFIX = "VMP_PLATFORM_REGISTER_INFO_";
  41 +
  42 + public static final String PLATFORM_SEND_RTP_INFO_PREFIX = "VMP_PLATFORM_SEND_RTP_INFO_";
  43 +
  44 + public static final String EVENT_ONLINE_REGISTER = "1";
  45 +
  46 + public static final String EVENT_ONLINE_MESSAGE = "3";
  47 +
  48 + public static final String EVENT_OUTLINE_UNREGISTER = "1";
  49 +
  50 + public static final String EVENT_OUTLINE_TIMEOUT = "2";
  51 +
  52 + public static final String MEDIA_SSRC_USED_PREFIX = "VMP_MEDIA_USED_SSRC_";
  53 +
  54 + public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_";
  55 +
  56 + public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_";
  57 +
  58 + public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_";
  59 +
  60 + public static final String SIP_SN_PREFIX = "VMP_SIP_SN_";
  61 +
  62 + public static final String SIP_SUBSCRIBE_PREFIX = "VMP_SIP_SUBSCRIBE_";
  63 +
  64 + public static final String SYSTEM_INFO_CPU_PREFIX = "VMP_SYSTEM_INFO_CPU_";
  65 +
  66 + public static final String SYSTEM_INFO_MEM_PREFIX = "VMP_SYSTEM_INFO_MEM_";
  67 +
  68 + public static final String SYSTEM_INFO_NET_PREFIX = "VMP_SYSTEM_INFO_NET_";
  69 +
  70 + public static final String SYSTEM_INFO_DISK_PREFIX = "VMP_SYSTEM_INFO_DISK_";
  71 + public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_";
  72 +
  73 + public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
  74 +
  75 +
  76 +
  77 +
  78 + //************************** redis 消息*********************************
  79 +
  80 + /**
  81 + * 流变化的通知
  82 + */
  83 + public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
  84 +
  85 + /**
  86 + * 接收推流设备的GPS变化通知
  87 + */
  88 + public static final String VM_MSG_GPS = "VM_MSG_GPS";
  89 +
  90 + /**
  91 + * 接收推流设备的GPS变化通知
  92 + */
  93 + public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE";
  94 + /**
  95 + * 接收推流设备列表更新变化通知
  96 + */
  97 + public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE";
  98 +
  99 + /**
  100 + * redis 消息通知设备推流到平台
  101 + */
  102 + public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED";
  103 +
  104 + /**
  105 + * redis 消息通知上级平台开始观看流
  106 + */
  107 + public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY";
  108 +
  109 + /**
  110 + * redis 消息通知上级平台停止观看流
  111 + */
  112 + public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY";
  113 +
  114 + /**
  115 + * redis 消息接收关闭一个推流
  116 + */
  117 + public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED";
  118 +
  119 +
  120 + /**
  121 + * redis 消息通知平台通知设备推流结果
  122 + */
  123 + public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
  124 +
  125 + /**
  126 + * redis 通知平台关闭推流
  127 + */
  128 + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
  129 +
  130 + /**
  131 + * redis 消息请求所有的在线通道
  132 + */
  133 + public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
  134 +
  135 + /**
  136 + * 移动位置订阅通知
  137 + */
  138 + public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition";
  139 +
  140 + /**
  141 + * 报警订阅的通知(收到报警向redis发出通知)
  142 + */
  143 + public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm";
  144 +
  145 +
  146 + /**
  147 + * 报警通知的发送 (收到redis发出的通知,转发给其他平台)
  148 + */
  149 + public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive";
  150 +
  151 + /**
  152 + * 设备状态订阅的通知
  153 + */
  154 + public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device";
  155 +
  156 +
  157 + //************************** 第三方 ****************************************
  158 +
  159 + public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
  160 + public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
  161 + public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_";
  162 + public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_";
  163 + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_";
  164 + public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_";
  165 +
  166 + /**
  167 + * Redis Const
  168 + * 设备录像信息结果前缀
  169 + */
  170 + public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";
  171 + /**
  172 + * Redis Const
  173 + * 设备录像信息结果前缀
  174 + */
  175 + public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
  176 +
  177 +}
... ...
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
... ... @@ -51,7 +51,7 @@ public class ApiAccessFilter extends OncePerRequestFilter {
51 51  
52 52 filterChain.doFilter(servletRequest, servletResponse);
53 53  
54   - if (uriName != null && userSetting != null && userSetting.getLogInDatebase() != null && userSetting.getLogInDatebase()) {
  54 + if (uriName != null && userSetting != null && userSetting.getLogInDatabase() != null && userSetting.getLogInDatabase()) {
55 55  
56 56 LogDto logDto = new LogDto();
57 57 logDto.setName(uriName);
... ...
src/main/java/com/genersoft/iot/vmp/conf/CivilCodeFileConf.java
... ... @@ -12,7 +12,10 @@ import org.springframework.core.annotation.Order;
12 12 import org.springframework.core.io.ClassPathResource;
13 13 import org.springframework.util.ObjectUtils;
14 14  
15   -import java.io.*;
  15 +import java.io.BufferedReader;
  16 +import java.io.File;
  17 +import java.io.InputStream;
  18 +import java.io.InputStreamReader;
16 19 import java.nio.file.Files;
17 20 import java.util.Map;
18 21  
... ...
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
... ... @@ -111,7 +111,7 @@ public class DynamicTask {
111 111 }
112 112 boolean result = false;
113 113 if (!ObjectUtils.isEmpty(futureMap.get(key)) && !futureMap.get(key).isCancelled() && !futureMap.get(key).isDone()) {
114   - result = futureMap.get(key).cancel(true);
  114 + result = futureMap.get(key).cancel(false);
115 115 futureMap.remove(key);
116 116 runnableMap.remove(key);
117 117 }
... ... @@ -143,7 +143,8 @@ public class DynamicTask {
143 143 public void execute(){
144 144 if (futureMap.size() > 0) {
145 145 for (String key : futureMap.keySet()) {
146   - if (futureMap.get(key).isDone() || futureMap.get(key).isCancelled()) {
  146 + ScheduledFuture<?> future = futureMap.get(key);
  147 + if (future.isDone() || future.isCancelled()) {
147 148 futureMap.remove(key);
148 149 runnableMap.remove(key);
149 150 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/ProxyServletConfig.java
... ... @@ -18,6 +18,7 @@ import org.springframework.util.ObjectUtils;
18 18  
19 19 import javax.servlet.ServletException;
20 20 import javax.servlet.http.HttpServletRequest;
  21 +import javax.servlet.http.HttpServletResponse;
21 22 import java.io.IOException;
22 23 import java.net.ConnectException;
23 24  
... ... @@ -64,6 +65,18 @@ public class ProxyServletConfig {
64 65 return queryStr;
65 66 }
66 67  
  68 +
  69 + @Override
  70 + protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
  71 + HttpRequest proxyRequest) throws IOException {
  72 + HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
  73 + response.removeHeaders("Access-Control-Allow-Origin");
  74 + response.setHeader("Access-Control-Allow-Credentials","true");
  75 + response.removeHeaders("Access-Control-Allow-Credentials");
  76 +
  77 + return response;
  78 + }
  79 +
67 80 /**
68 81 * 异常处理
69 82 */
... ... @@ -181,6 +194,18 @@ public class ProxyServletConfig {
181 194 return queryStr;
182 195 }
183 196  
  197 +
  198 + @Override
  199 + protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse,
  200 + HttpRequest proxyRequest) throws IOException {
  201 + HttpResponse response = super.doExecute(servletRequest, servletResponse, proxyRequest);
  202 + String origin = servletRequest.getHeader("origin");
  203 + response.setHeader("Access-Control-Allow-Origin",origin);
  204 + response.setHeader("Access-Control-Allow-Credentials","true");
  205 +
  206 + return response;
  207 + }
  208 +
184 209 /**
185 210 * 异常处理
186 211 */
... ...
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
... ... @@ -4,8 +4,11 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
5 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
6 6 import com.genersoft.iot.vmp.service.IPlatformService;
  7 +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
7 8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
8 9 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
9 12 import org.springframework.beans.factory.annotation.Autowired;
10 13 import org.springframework.boot.CommandLineRunner;
11 14 import org.springframework.core.annotation.Order;
... ... @@ -33,6 +36,7 @@ public class SipPlatformRunner implements CommandLineRunner {
33 36 @Autowired
34 37 private ISIPCommanderForPlatform sipCommanderForPlatform;
35 38  
  39 + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
36 40  
37 41 @Override
38 42 public void run(String... args) throws Exception {
... ... @@ -50,9 +54,15 @@ public class SipPlatformRunner implements CommandLineRunner {
50 54 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
51 55 if (parentPlatformCatchOld != null) {
52 56 // 取消订阅
53   - sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
54   - platformService.login(parentPlatform);
55   - });
  57 + try {
  58 + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
  59 + platformService.login(parentPlatform);
  60 + });
  61 + } catch (Exception e) {
  62 + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
  63 + platformService.offline(parentPlatform, true);
  64 + continue;
  65 + }
56 66 }
57 67  
58 68 // 设置所有平台离线
... ...
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
... ... @@ -31,7 +31,7 @@ public class UserSetting {
31 31  
32 32 private Boolean recordSip = Boolean.TRUE;
33 33  
34   - private Boolean logInDatebase = Boolean.TRUE;
  34 + private Boolean logInDatabase = Boolean.TRUE;
35 35  
36 36 private Boolean usePushingAsStatus = Boolean.FALSE;
37 37  
... ... @@ -134,12 +134,12 @@ public class UserSetting {
134 134 this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes;
135 135 }
136 136  
137   - public Boolean getLogInDatebase() {
138   - return logInDatebase;
  137 + public Boolean getLogInDatabase() {
  138 + return logInDatabase;
139 139 }
140 140  
141   - public void setLogInDatebase(Boolean logInDatebase) {
142   - this.logInDatebase = logInDatebase;
  141 + public void setLogInDatabase(Boolean logInDatabase) {
  142 + this.logInDatabase = logInDatabase;
143 143 }
144 144  
145 145 public String getServerId() {
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
1 1 package com.genersoft.iot.vmp.conf.security;
2 2  
3 3 import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
4   -import org.jose4j.json.JsonUtil;
  4 +import com.genersoft.iot.vmp.service.IUserService;
  5 +import com.genersoft.iot.vmp.storager.dao.dto.User;
5 6 import org.jose4j.jwk.RsaJsonWebKey;
  7 +import org.jose4j.jwk.RsaJwkGenerator;
6 8 import org.jose4j.jws.AlgorithmIdentifiers;
7 9 import org.jose4j.jws.JsonWebSignature;
8 10 import org.jose4j.jwt.JwtClaims;
... ... @@ -14,45 +16,69 @@ import org.jose4j.jwt.consumer.JwtConsumerBuilder;
14 16 import org.jose4j.lang.JoseException;
15 17 import org.slf4j.Logger;
16 18 import org.slf4j.LoggerFactory;
  19 +import org.springframework.beans.factory.InitializingBean;
  20 +import org.springframework.stereotype.Component;
17 21  
18   -import java.security.PrivateKey;
  22 +import javax.annotation.Resource;
19 23 import java.time.LocalDateTime;
20 24 import java.time.ZoneOffset;
21 25  
22   -public class JwtUtils {
  26 +@Component
  27 +public class JwtUtils implements InitializingBean {
23 28  
24 29 private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
25 30  
26 31 private static final String HEADER = "access-token";
27   - private static final String AUDIENCE = "Audience";
28 32  
29   - private static final long EXPIRED_THRESHOLD = 10 * 60;
  33 + private static final String AUDIENCE = "Audience";
30 34  
31 35 private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
32   - private static final String privateKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\",\"d\":\"ed7U_k3rJ4yTk70JtRSIfjKGiEb67BO1TabcymnljKO7RU8nage84zZYuSu_XpQsHk6P1f0Gzxkicghm_Er-FrfVn2pp70Xu52z3yRd6BJUgWLDFk97ngScIyw5OiULKU9SrZk2frDpftNCSUcIgb50F8m0QAnBa_CdPsQKbuuhLv8V8tBAV7F_lAwvSBgu56wRo3hPz5dWH8YeXM7XBfQ9viFMNEKd21sP_j5C7ueUnXT66nBxe3ZJEU3iuMYM6D6dB_KW2GfZC6WmTgvGhhxJD0h7aYmfjkD99MDleB7SkpbvoODOqiQ5Epb7Nyh6kv5u4KUv2CJYtATLZkUeMkQ\",\"p\":\"uBUjWPWtlGksmOqsqCNWksfqJvMcnP_8TDYN7e4-WnHL4N-9HjRuPDnp6kHvCIEi9SEfxm7gNxlRcWegvNQr3IZCz7TnCTexXc5NOklB9OavWFla6u-s3Thn6Tz45-EUjpJr0VJMxhO-KxGmuTwUXBBp4vN6K2qV6rQNFmgkWzk\",\"q\":\"tW_i7cCec56bHkhITL_79dXHz_PLC_f7xlynmlZJGU_d6mqOKmLBNBbTMLnYW8uAFiFzWxDeDHh1o5uF0mSQR-Z1Fg35OftnpbWpy0Cbc2la5WgXQjOwtG1eLYIY2BD3-wQ1VYDBCvowr4FDi-sngxwLqvwmrJ0xjhi99O-Gzcs\",\"dp\":\"q1d5jE85Hz_6M-eTh_lEluEf0NtPEc-vvhw-QO4V-cecNpbrCBdTWBmr4dE3NdpFeJc5ZVFEv-SACyei1MBEh0ItI_pFZi4BmMfy2ELh8ptaMMkTOESYyVy8U7veDq9RnBcr5i1Nqr0rsBkA77-9T6gzdvycBZdzLYAkAmwzEvk\",\"dq\":\"q29A2K08Crs-jmp2Bi8Q_8QzvIX6wSBbwZ4ir24AO-5_HNP56IrPS0yV2GCB0pqCOGb6_Hz_koDvhtuYoqdqvMVAtMoXR3YJBUaVXPt65p4RyNmFwIPe31zHs_BNUTsXVRMw4c16mci03-Af1sEm4HdLfxAp6sfM3xr5wcnhcek\",\"qi\":\"rHPgVTyHUHuYzcxfouyBfb1XAY8nshwn0ddo81o1BccD4Z7zo5It6SefDHjxCAbcmbiCcXBSooLcY-NF5FMv3fg19UE21VyLQltHcVjRRp2tRs4OHcM8yaXIU2x6N6Z6BP2tOksHb9MOBY1wAQzFOAKg_G4Sxev6-_6ud6RISuc\"}";
33   - private static final String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\"}";
34 36  
35 37 /**
36 38 * token过期时间(分钟)
37 39 */
38   - public static final long expirationTime = 30;
  40 + public static final long expirationTime = 30 * 24 * 60;
  41 +
  42 + private static RsaJsonWebKey rsaJsonWebKey;
39 43  
40   - public static String createToken(String username, String password, Integer roleId) {
  44 + private static IUserService userService;
  45 +
  46 + @Resource
  47 + public void setUserService(IUserService userService) {
  48 + JwtUtils.userService = userService;
  49 + }
  50 +
  51 + @Override
  52 + public void afterPropertiesSet() {
41 53 try {
42   - /**
  54 + rsaJsonWebKey = generateRsaJsonWebKey();
  55 + } catch (JoseException e) {
  56 + logger.error("生成RsaJsonWebKey报错。", e);
  57 + }
  58 + }
  59 +
  60 + /**
  61 + * 创建密钥对
  62 + * @throws JoseException JoseException
  63 + */
  64 + private RsaJsonWebKey generateRsaJsonWebKey() throws JoseException {
  65 + // 生成一个RSA密钥对,该密钥对将用于JWT的签名和验证,包装在JWK中
  66 + RsaJsonWebKey rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
  67 + // 给JWK一个密钥ID
  68 + rsaJsonWebKey.setKeyId(keyId);
  69 + return rsaJsonWebKey;
  70 + }
  71 +
  72 + public static String createToken(String username) {
  73 + try {
  74 + /*
43 75 * “iss” (issuer) 发行人
44   - *
45 76 * “sub” (subject) 主题
46   - *
47 77 * “aud” (audience) 接收方 用户
48   - *
49 78 * “exp” (expiration time) 到期时间
50   - *
51 79 * “nbf” (not before) 在此之前不可用
52   - *
53 80 * “iat” (issued at) jwt的签发时间
54 81 */
55   - //Payload
56 82 JwtClaims claims = new JwtClaims();
57 83 claims.setGeneratedJwtId();
58 84 claims.setIssuedAtToNow();
... ... @@ -62,9 +88,7 @@ public class JwtUtils {
62 88 claims.setSubject("login");
63 89 claims.setAudience(AUDIENCE);
64 90 //添加自定义参数,必须是字符串类型
65   - claims.setClaim("username", username);
66   - claims.setClaim("password", password);
67   - claims.setClaim("roleId", roleId);
  91 + claims.setClaim("userName", username);
68 92  
69 93 //jws
70 94 JsonWebSignature jws = new JsonWebSignature();
... ... @@ -73,12 +97,10 @@ public class JwtUtils {
73 97 jws.setKeyIdHeaderValue(keyId);
74 98 jws.setPayload(claims.toJson());
75 99  
76   - PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
77   - jws.setKey(privateKey);
  100 + jws.setKey(rsaJsonWebKey.getPrivateKey());
78 101  
79 102 //get token
80   - String idToken = jws.getCompactSerialization();
81   - return idToken;
  103 + return jws.getCompactSerialization();
82 104 } catch (JoseException e) {
83 105 logger.error("[Token生成失败]: {}", e.getMessage());
84 106 }
... ... @@ -90,7 +112,6 @@ public class JwtUtils {
90 112 return HEADER;
91 113 }
92 114  
93   -
94 115 public static JwtUser verifyToken(String token) {
95 116  
96 117 JwtUser jwtUser = new JwtUser();
... ... @@ -103,7 +124,7 @@ public class JwtUtils {
103 124 .setRequireSubject()
104 125 //.setExpectedIssuer("")
105 126 .setExpectedAudience(AUDIENCE)
106   - .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
  127 + .setVerificationKey(rsaJsonWebKey.getPublicKey())
107 128 .build();
108 129  
109 130 JwtClaims claims = consumer.processToClaims(token);
... ... @@ -113,26 +134,26 @@ public class JwtUtils {
113 134 long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
114 135 if (timeRemaining < 5 * 60) {
115 136 jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
116   - }else {
  137 + } else {
117 138 jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
118 139 }
119 140  
120   - String username = (String) claims.getClaimValue("username");
121   - String password = (String) claims.getClaimValue("password");
122   - Long roleId = (Long) claims.getClaimValue("roleId");
  141 + String username = (String) claims.getClaimValue("userName");
  142 + User user = userService.getUserByUsername(username);
  143 +
123 144 jwtUser.setUserName(username);
124   - jwtUser.setPassword(password);
125   - jwtUser.setRoleId(roleId.intValue());
  145 + jwtUser.setPassword(user.getPassword());
  146 + jwtUser.setRoleId(user.getRole().getId());
126 147  
127 148 return jwtUser;
128 149 } catch (InvalidJwtException e) {
129 150 if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
130 151 jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
131   - }else {
  152 + } else {
132 153 jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
133 154 }
134 155 return jwtUser;
135   - }catch (Exception e) {
  156 + } catch (Exception e) {
136 157 logger.error("[Token解析失败]: {}", e.getMessage());
137 158 jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
138 159 return jwtUser;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
1   -package com.genersoft.iot.vmp.gb28181;
2   -
3   -import com.genersoft.iot.vmp.conf.SipConfig;
4   -import com.genersoft.iot.vmp.conf.UserSetting;
5   -import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory;
6   -import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties;
7   -import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver;
8   -import gov.nist.javax.sip.SipProviderImpl;
9   -import gov.nist.javax.sip.SipStackImpl;
10   -import org.slf4j.Logger;
11   -import org.slf4j.LoggerFactory;
12   -import org.springframework.beans.factory.annotation.Autowired;
13   -import org.springframework.boot.CommandLineRunner;
14   -import org.springframework.core.annotation.Order;
15   -import org.springframework.stereotype.Component;
16   -import org.springframework.util.ObjectUtils;
17   -
18   -import javax.sip.*;
19   -import java.util.*;
20   -import java.util.concurrent.ConcurrentHashMap;
21   -
22   -@Component
23   -@Order(value=10)
24   -public class SipLayer implements CommandLineRunner {
25   -
26   - private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
27   -
28   - @Autowired
29   - private SipConfig sipConfig;
30   -
31   - @Autowired
32   - private ISIPProcessorObserver sipProcessorObserver;
33   -
34   - @Autowired
35   - private UserSetting userSetting;
36   -
37   - private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>();
38   - private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>();
39   -
40   - @Override
41   - public void run(String... args) {
42   - List<String> monitorIps = new ArrayList<>();
43   - // 使用逗号分割多个ip
44   - String separator = ",";
45   - if (sipConfig.getIp().indexOf(separator) > 0) {
46   - String[] split = sipConfig.getIp().split(separator);
47   - monitorIps.addAll(Arrays.asList(split));
48   - }else {
49   - monitorIps.add(sipConfig.getIp());
50   - }
51   -
52   - SipFactory.getInstance().setPathName("gov.nist");
53   - if (monitorIps.size() > 0) {
54   - for (String monitorIp : monitorIps) {
55   - addListeningPoint(monitorIp, sipConfig.getPort());
56   - }
57   - if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) {
58   - System.exit(1);
59   - }
60   - }
61   - }
62   -
63   - private void addListeningPoint(String monitorIp, int port){
64   - SipStackImpl sipStack;
65   - try {
66   - sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog()));
67   - sipStack.setMessageParserFactory(new GbStringMsgParserFactory());
68   - } catch (PeerUnavailableException e) {
69   - logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp);
70   - return;
71   - }
72   -
73   - try {
74   - ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP");
75   - SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
76   -
77   - tcpSipProvider.setDialogErrorsAutomaticallyHandled();
78   - tcpSipProvider.addSipListener(sipProcessorObserver);
79   - tcpSipProviderMap.put(monitorIp, tcpSipProvider);
80   - logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port);
81   - } catch (TransportNotSupportedException
82   - | TooManyListenersException
83   - | ObjectInUseException
84   - | InvalidArgumentException e) {
85   - logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确"
86   - , monitorIp, port);
87   - }
88   -
89   - try {
90   - ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP");
91   -
92   - SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
93   - udpSipProvider.addSipListener(sipProcessorObserver);
94   -
95   - udpSipProviderMap.put(monitorIp, udpSipProvider);
96   -
97   - logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port);
98   - } catch (TransportNotSupportedException
99   - | TooManyListenersException
100   - | ObjectInUseException
101   - | InvalidArgumentException e) {
102   - logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确"
103   - , monitorIp, port);
104   - }
105   - }
106   -
107   - public SipProviderImpl getUdpSipProvider(String ip) {
108   - if (ObjectUtils.isEmpty(ip)) {
109   - return null;
110   - }
111   - return udpSipProviderMap.get(ip);
112   - }
113   -
114   - public SipProviderImpl getUdpSipProvider() {
115   - if (udpSipProviderMap.size() != 1) {
116   - return null;
117   - }
118   - return udpSipProviderMap.values().stream().findFirst().get();
119   - }
120   -
121   - public SipProviderImpl getTcpSipProvider() {
122   - if (tcpSipProviderMap.size() != 1) {
123   - return null;
124   - }
125   - return tcpSipProviderMap.values().stream().findFirst().get();
126   - }
127   -
128   - public SipProviderImpl getTcpSipProvider(String ip) {
129   - if (ObjectUtils.isEmpty(ip)) {
130   - return null;
131   - }
132   - return tcpSipProviderMap.get(ip);
133   - }
134   -
135   - public String getLocalIp(String deviceLocalIp) {
136   - if (!ObjectUtils.isEmpty(deviceLocalIp)) {
137   - return deviceLocalIp;
138   - }
139   - return getUdpSipProvider().getListeningPoint().getIPAddress();
140   - }
141   -}
  1 +package com.genersoft.iot.vmp.gb28181;
  2 +
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
  5 +import com.genersoft.iot.vmp.gb28181.bean.GbStringMsgParserFactory;
  6 +import com.genersoft.iot.vmp.gb28181.conf.DefaultProperties;
  7 +import com.genersoft.iot.vmp.gb28181.transmit.ISIPProcessorObserver;
  8 +import gov.nist.javax.sip.SipProviderImpl;
  9 +import gov.nist.javax.sip.SipStackImpl;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
  12 +import org.springframework.beans.factory.annotation.Autowired;
  13 +import org.springframework.boot.CommandLineRunner;
  14 +import org.springframework.core.annotation.Order;
  15 +import org.springframework.stereotype.Component;
  16 +import org.springframework.util.ObjectUtils;
  17 +
  18 +import javax.sip.*;
  19 +import java.util.*;
  20 +import java.util.concurrent.ConcurrentHashMap;
  21 +
  22 +@Component
  23 +@Order(value=10)
  24 +public class SipLayer implements CommandLineRunner {
  25 +
  26 + private final static Logger logger = LoggerFactory.getLogger(SipLayer.class);
  27 +
  28 + @Autowired
  29 + private SipConfig sipConfig;
  30 +
  31 + @Autowired
  32 + private ISIPProcessorObserver sipProcessorObserver;
  33 +
  34 + @Autowired
  35 + private UserSetting userSetting;
  36 +
  37 + private final Map<String, SipProviderImpl> tcpSipProviderMap = new ConcurrentHashMap<>();
  38 + private final Map<String, SipProviderImpl> udpSipProviderMap = new ConcurrentHashMap<>();
  39 +
  40 + @Override
  41 + public void run(String... args) {
  42 + List<String> monitorIps = new ArrayList<>();
  43 + // 使用逗号分割多个ip
  44 + String separator = ",";
  45 + if (sipConfig.getIp().indexOf(separator) > 0) {
  46 + String[] split = sipConfig.getIp().split(separator);
  47 + monitorIps.addAll(Arrays.asList(split));
  48 + }else {
  49 + monitorIps.add(sipConfig.getIp());
  50 + }
  51 +
  52 + SipFactory.getInstance().setPathName("gov.nist");
  53 + if (monitorIps.size() > 0) {
  54 + for (String monitorIp : monitorIps) {
  55 + addListeningPoint(monitorIp, sipConfig.getPort());
  56 + }
  57 + if (udpSipProviderMap.size() + tcpSipProviderMap.size() == 0) {
  58 + System.exit(1);
  59 + }
  60 + }
  61 + }
  62 +
  63 + private void addListeningPoint(String monitorIp, int port){
  64 + SipStackImpl sipStack;
  65 + try {
  66 + sipStack = (SipStackImpl)SipFactory.getInstance().createSipStack(DefaultProperties.getProperties("GB28181_SIP", userSetting.getSipLog()));
  67 + sipStack.setMessageParserFactory(new GbStringMsgParserFactory());
  68 + } catch (PeerUnavailableException e) {
  69 + logger.error("[SIP SERVER] SIP服务启动失败, 监听地址{}失败,请检查ip是否正确", monitorIp);
  70 + return;
  71 + }
  72 +
  73 + try {
  74 + ListeningPoint tcpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "TCP");
  75 + SipProviderImpl tcpSipProvider = (SipProviderImpl)sipStack.createSipProvider(tcpListeningPoint);
  76 +
  77 + tcpSipProvider.setDialogErrorsAutomaticallyHandled();
  78 + tcpSipProvider.addSipListener(sipProcessorObserver);
  79 + tcpSipProviderMap.put(monitorIp, tcpSipProvider);
  80 + logger.info("[SIP SERVER] tcp://{}:{} 启动成功", monitorIp, port);
  81 + } catch (TransportNotSupportedException
  82 + | TooManyListenersException
  83 + | ObjectInUseException
  84 + | InvalidArgumentException e) {
  85 + logger.error("[SIP SERVER] tcp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确"
  86 + , monitorIp, port);
  87 + }
  88 +
  89 + try {
  90 + ListeningPoint udpListeningPoint = sipStack.createListeningPoint(monitorIp, port, "UDP");
  91 +
  92 + SipProviderImpl udpSipProvider = (SipProviderImpl)sipStack.createSipProvider(udpListeningPoint);
  93 + udpSipProvider.addSipListener(sipProcessorObserver);
  94 +
  95 + udpSipProviderMap.put(monitorIp, udpSipProvider);
  96 +
  97 + logger.info("[SIP SERVER] udp://{}:{} 启动成功", monitorIp, port);
  98 + } catch (TransportNotSupportedException
  99 + | TooManyListenersException
  100 + | ObjectInUseException
  101 + | InvalidArgumentException e) {
  102 + logger.error("[SIP SERVER] udp://{}:{} SIP服务启动失败,请检查端口是否被占用或者ip是否正确"
  103 + , monitorIp, port);
  104 + }
  105 + }
  106 +
  107 + public SipProviderImpl getUdpSipProvider(String ip) {
  108 + if (ObjectUtils.isEmpty(ip)) {
  109 + return null;
  110 + }
  111 + return udpSipProviderMap.get(ip);
  112 + }
  113 +
  114 + public SipProviderImpl getUdpSipProvider() {
  115 + if (udpSipProviderMap.size() != 1) {
  116 + return null;
  117 + }
  118 + return udpSipProviderMap.values().stream().findFirst().get();
  119 + }
  120 +
  121 + public SipProviderImpl getTcpSipProvider() {
  122 + if (tcpSipProviderMap.size() != 1) {
  123 + return null;
  124 + }
  125 + return tcpSipProviderMap.values().stream().findFirst().get();
  126 + }
  127 +
  128 + public SipProviderImpl getTcpSipProvider(String ip) {
  129 + if (ObjectUtils.isEmpty(ip)) {
  130 + return null;
  131 + }
  132 + return tcpSipProviderMap.get(ip);
  133 + }
  134 +
  135 + public String getLocalIp(String deviceLocalIp) {
  136 + if (!ObjectUtils.isEmpty(deviceLocalIp)) {
  137 + return deviceLocalIp;
  138 + }
  139 + return getUdpSipProvider().getListeningPoint().getIPAddress();
  140 + }
  141 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceAlarm.java
1   -package com.genersoft.iot.vmp.gb28181.bean;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -
5   -/**
6   - * @author lin
7   - */
8   -@Schema(description = "报警信息")
9   -public class DeviceAlarm {
10   -
11   - /**
12   - * 数据库id
13   - */
14   - @Schema(description = "数据库id")
15   - private String id;
16   -
17   - /**
18   - * 设备Id
19   - */
20   - @Schema(description = "设备的国标编号")
21   - private String deviceId;
22   -
23   - /**
24   - * 通道Id
25   - */
26   - @Schema(description = "通道的国标编号")
27   - private String channelId;
28   -
29   - /**
30   - * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情
31   - */
32   - @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情")
33   - private String alarmPriority;
34   -
35   - /**
36   - * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
37   - * 7其他报警;可以为直接组合如12为电话报警或 设备报警-
38   - */
39   - @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" +
40   - "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警")
41   - private String alarmMethod;
42   -
43   - /**
44   - * 报警时间
45   - */
46   - @Schema(description = "报警时间")
47   - private String alarmTime;
48   -
49   - /**
50   - * 报警内容描述
51   - */
52   - @Schema(description = "报警内容描述")
53   - private String alarmDescription;
54   -
55   - /**
56   - * 经度
57   - */
58   - @Schema(description = "经度")
59   - private double longitude;
60   -
61   - /**
62   - * 纬度
63   - */
64   - @Schema(description = "纬度")
65   - private double latitude;
66   -
67   - /**
68   - * 报警类型,
69   - * 报警方式为2时,不携带 AlarmType为默认的报警设备报警,
70   - * 携带 AlarmType取值及对应报警类型如下:
71   - * 1-视频丢失报警;
72   - * 2-设备防拆报警;
73   - * 3-存储设备磁盘满报警;
74   - * 4-设备高温报警;
75   - * 5-设备低温报警。
76   - * 报警方式为5时,取值如下:
77   - * 1-人工视频报警;
78   - * 2-运动目标检测报警;
79   - * 3-遗留物检测报警;
80   - * 4-物体移除检测报警;
81   - * 5-绊线检测报警;
82   - * 6-入侵检测报警;
83   - * 7-逆行检测报警;
84   - * 8-徘徊检测报警;
85   - * 9-流量统计报警;
86   - * 10-密度检测报警;
87   - * 11-视频异常检测报警;
88   - * 12-快速移动报警。
89   - * 报警方式为6时,取值下:
90   - * 1-存储设备磁盘故障报警;
91   - * 2-存储设备风扇故障报警。
92   - */
93   - @Schema(description = "报警类型")
94   - private String alarmType;
95   -
96   - @Schema(description = "创建时间")
97   - private String createTime;
98   -
99   -
100   - public String getId() {
101   - return id;
102   - }
103   -
104   - public void setId(String id) {
105   - this.id = id;
106   - }
107   -
108   - public String getDeviceId() {
109   - return deviceId;
110   - }
111   -
112   - public void setDeviceId(String deviceId) {
113   - this.deviceId = deviceId;
114   - }
115   -
116   - public String getAlarmPriority() {
117   - return alarmPriority;
118   - }
119   -
120   - public void setAlarmPriority(String alarmPriority) {
121   - this.alarmPriority = alarmPriority;
122   - }
123   -
124   - public String getAlarmMethod() {
125   - return alarmMethod;
126   - }
127   -
128   - public void setAlarmMethod(String alarmMethod) {
129   - this.alarmMethod = alarmMethod;
130   - }
131   -
132   - public String getAlarmTime() {
133   - return alarmTime;
134   - }
135   -
136   - public void setAlarmTime(String alarmTime) {
137   - this.alarmTime = alarmTime;
138   - }
139   -
140   - public String getAlarmDescription() {
141   - return alarmDescription;
142   - }
143   -
144   - public void setAlarmDescription(String alarmDescription) {
145   - this.alarmDescription = alarmDescription;
146   - }
147   -
148   - public double getLongitude() {
149   - return longitude;
150   - }
151   -
152   - public void setLongitude(double longitude) {
153   - this.longitude = longitude;
154   - }
155   -
156   - public double getLatitude() {
157   - return latitude;
158   - }
159   -
160   - public void setLatitude(double latitude) {
161   - this.latitude = latitude;
162   - }
163   -
164   - public String getAlarmType() {
165   - return alarmType;
166   - }
167   -
168   - public void setAlarmType(String alarmType) {
169   - this.alarmType = alarmType;
170   - }
171   -
172   - public String getChannelId() {
173   - return channelId;
174   - }
175   -
176   - public void setChannelId(String channelId) {
177   - this.channelId = channelId;
178   - }
179   -
180   - public String getCreateTime() {
181   - return createTime;
182   - }
183   -
184   - public void setCreateTime(String createTime) {
185   - this.createTime = createTime;
186   - }
187   -}
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +
  5 +/**
  6 + * @author lin
  7 + */
  8 +@Schema(description = "报警信息")
  9 +public class DeviceAlarm {
  10 +
  11 + /**
  12 + * 数据库id
  13 + */
  14 + @Schema(description = "数据库id")
  15 + private String id;
  16 +
  17 + /**
  18 + * 设备Id
  19 + */
  20 + @Schema(description = "设备的国标编号")
  21 + private String deviceId;
  22 +
  23 + /**
  24 + * 通道Id
  25 + */
  26 + @Schema(description = "通道的国标编号")
  27 + private String channelId;
  28 +
  29 + /**
  30 + * 报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情
  31 + */
  32 + @Schema(description = "报警级别, 1为一级警情, 2为二级警情, 3为三级警情, 4为四级警情")
  33 + private String alarmPriority;
  34 +
  35 + /**
  36 + * 报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,
  37 + * 7其他报警;可以为直接组合如12为电话报警或 设备报警-
  38 + */
  39 + @Schema(description = "报警方式 , 1为电话报警, 2为设备报警, 3为短信报警, 4为 GPS报警, 5为视频报警, 6为设备故障报警,\n" +
  40 + "\t * 7其他报警;可以为直接组合如12为电话报警或设备报警")
  41 + private String alarmMethod;
  42 +
  43 + /**
  44 + * 报警时间
  45 + */
  46 + @Schema(description = "报警时间")
  47 + private String alarmTime;
  48 +
  49 + /**
  50 + * 报警内容描述
  51 + */
  52 + @Schema(description = "报警内容描述")
  53 + private String alarmDescription;
  54 +
  55 + /**
  56 + * 经度
  57 + */
  58 + @Schema(description = "经度")
  59 + private double longitude;
  60 +
  61 + /**
  62 + * 纬度
  63 + */
  64 + @Schema(description = "纬度")
  65 + private double latitude;
  66 +
  67 + /**
  68 + * 报警类型,
  69 + * 报警方式为2时,不携带 AlarmType为默认的报警设备报警,
  70 + * 携带 AlarmType取值及对应报警类型如下:
  71 + * 1-视频丢失报警;
  72 + * 2-设备防拆报警;
  73 + * 3-存储设备磁盘满报警;
  74 + * 4-设备高温报警;
  75 + * 5-设备低温报警。
  76 + * 报警方式为5时,取值如下:
  77 + * 1-人工视频报警;
  78 + * 2-运动目标检测报警;
  79 + * 3-遗留物检测报警;
  80 + * 4-物体移除检测报警;
  81 + * 5-绊线检测报警;
  82 + * 6-入侵检测报警;
  83 + * 7-逆行检测报警;
  84 + * 8-徘徊检测报警;
  85 + * 9-流量统计报警;
  86 + * 10-密度检测报警;
  87 + * 11-视频异常检测报警;
  88 + * 12-快速移动报警。
  89 + * 报警方式为6时,取值下:
  90 + * 1-存储设备磁盘故障报警;
  91 + * 2-存储设备风扇故障报警。
  92 + */
  93 + @Schema(description = "报警类型")
  94 + private String alarmType;
  95 +
  96 + @Schema(description = "创建时间")
  97 + private String createTime;
  98 +
  99 +
  100 + public String getId() {
  101 + return id;
  102 + }
  103 +
  104 + public void setId(String id) {
  105 + this.id = id;
  106 + }
  107 +
  108 + public String getDeviceId() {
  109 + return deviceId;
  110 + }
  111 +
  112 + public void setDeviceId(String deviceId) {
  113 + this.deviceId = deviceId;
  114 + }
  115 +
  116 + public String getAlarmPriority() {
  117 + return alarmPriority;
  118 + }
  119 +
  120 + public void setAlarmPriority(String alarmPriority) {
  121 + this.alarmPriority = alarmPriority;
  122 + }
  123 +
  124 + public String getAlarmMethod() {
  125 + return alarmMethod;
  126 + }
  127 +
  128 + public void setAlarmMethod(String alarmMethod) {
  129 + this.alarmMethod = alarmMethod;
  130 + }
  131 +
  132 + public String getAlarmTime() {
  133 + return alarmTime;
  134 + }
  135 +
  136 + public void setAlarmTime(String alarmTime) {
  137 + this.alarmTime = alarmTime;
  138 + }
  139 +
  140 + public String getAlarmDescription() {
  141 + return alarmDescription;
  142 + }
  143 +
  144 + public void setAlarmDescription(String alarmDescription) {
  145 + this.alarmDescription = alarmDescription;
  146 + }
  147 +
  148 + public double getLongitude() {
  149 + return longitude;
  150 + }
  151 +
  152 + public void setLongitude(double longitude) {
  153 + this.longitude = longitude;
  154 + }
  155 +
  156 + public double getLatitude() {
  157 + return latitude;
  158 + }
  159 +
  160 + public void setLatitude(double latitude) {
  161 + this.latitude = latitude;
  162 + }
  163 +
  164 + public String getAlarmType() {
  165 + return alarmType;
  166 + }
  167 +
  168 + public void setAlarmType(String alarmType) {
  169 + this.alarmType = alarmType;
  170 + }
  171 +
  172 + public String getChannelId() {
  173 + return channelId;
  174 + }
  175 +
  176 + public void setChannelId(String channelId) {
  177 + this.channelId = channelId;
  178 + }
  179 +
  180 + public String getCreateTime() {
  181 + return createTime;
  182 + }
  183 +
  184 + public void setCreateTime(String createTime) {
  185 + this.createTime = createTime;
  186 + }
  187 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GBStringMsgParser.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStream.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/GbStringMsgParserFactory.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HandlerCatchData.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/HomePositionRequest.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Host.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamCallback.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteStreamType.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/MobilePosition.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatform.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/ParentPlatformCatch.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformCatalog.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformGbStream.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PlatformRegister.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/PresetQuerySipReq.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.bean;
2   -
3   -
4   -import io.swagger.v3.oas.annotations.media.Schema;
5   -
6   -import java.time.Instant;
7   -import java.util.List;
8   -
9   -/**
10   - * @description:设备录像信息bean
11   - * @author: swwheihei
12   - * @date: 2020年5月8日 下午2:05:56
13   - */
14   -@Schema(description = "设备录像查询结果信息")
15   -public class RecordInfo {
16   -
17   - @Schema(description = "设备编号")
18   - private String deviceId;
19   -
20   - @Schema(description = "通道编号")
21   - private String channelId;
22   -
23   - @Schema(description = "命令序列号")
24   - private String sn;
25   -
26   - @Schema(description = "设备名称")
27   - private String name;
28   -
29   - @Schema(description = "列表总数")
30   - private int sumNum;
31   -
32   - private int count;
33   -
34   - private Instant lastTime;
35   -
36   - @Schema(description = "")
37   - private List<RecordItem> recordList;
38   -
39   - public String getDeviceId() {
40   - return deviceId;
41   - }
42   -
43   - public void setDeviceId(String deviceId) {
44   - this.deviceId = deviceId;
45   - }
46   -
47   - public String getName() {
48   - return name;
49   - }
50   -
51   - public void setName(String name) {
52   - this.name = name;
53   - }
54   -
55   - public int getSumNum() {
56   - return sumNum;
57   - }
58   -
59   - public void setSumNum(int sumNum) {
60   - this.sumNum = sumNum;
61   - }
62   -
63   - public List<RecordItem> getRecordList() {
64   - return recordList;
65   - }
66   -
67   - public void setRecordList(List<RecordItem> recordList) {
68   - this.recordList = recordList;
69   - }
70   -
71   - public String getChannelId() {
72   - return channelId;
73   - }
74   -
75   - public void setChannelId(String channelId) {
76   - this.channelId = channelId;
77   - }
78   -
79   - public String getSn() {
80   - return sn;
81   - }
82   -
83   - public void setSn(String sn) {
84   - this.sn = sn;
85   - }
86   -
87   - public Instant getLastTime() {
88   - return lastTime;
89   - }
90   -
91   - public void setLastTime(Instant lastTime) {
92   - this.lastTime = lastTime;
93   - }
94   -
95   - public int getCount() {
96   - return count;
97   - }
98   -
99   - public void setCount(int count) {
100   - this.count = count;
101   - }
102   -}
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +
  6 +import java.time.Instant;
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * @description:设备录像信息bean
  11 + * @author: swwheihei
  12 + * @date: 2020年5月8日 下午2:05:56
  13 + */
  14 +@Schema(description = "设备录像查询结果信息")
  15 +public class RecordInfo {
  16 +
  17 + @Schema(description = "设备编号")
  18 + private String deviceId;
  19 +
  20 + @Schema(description = "通道编号")
  21 + private String channelId;
  22 +
  23 + @Schema(description = "命令序列号")
  24 + private String sn;
  25 +
  26 + @Schema(description = "设备名称")
  27 + private String name;
  28 +
  29 + @Schema(description = "列表总数")
  30 + private int sumNum;
  31 +
  32 + private int count;
  33 +
  34 + private Instant lastTime;
  35 +
  36 + @Schema(description = "")
  37 + private List<RecordItem> recordList;
  38 +
  39 + public String getDeviceId() {
  40 + return deviceId;
  41 + }
  42 +
  43 + public void setDeviceId(String deviceId) {
  44 + this.deviceId = deviceId;
  45 + }
  46 +
  47 + public String getName() {
  48 + return name;
  49 + }
  50 +
  51 + public void setName(String name) {
  52 + this.name = name;
  53 + }
  54 +
  55 + public int getSumNum() {
  56 + return sumNum;
  57 + }
  58 +
  59 + public void setSumNum(int sumNum) {
  60 + this.sumNum = sumNum;
  61 + }
  62 +
  63 + public List<RecordItem> getRecordList() {
  64 + return recordList;
  65 + }
  66 +
  67 + public void setRecordList(List<RecordItem> recordList) {
  68 + this.recordList = recordList;
  69 + }
  70 +
  71 + public String getChannelId() {
  72 + return channelId;
  73 + }
  74 +
  75 + public void setChannelId(String channelId) {
  76 + this.channelId = channelId;
  77 + }
  78 +
  79 + public String getSn() {
  80 + return sn;
  81 + }
  82 +
  83 + public void setSn(String sn) {
  84 + this.sn = sn;
  85 + }
  86 +
  87 + public Instant getLastTime() {
  88 + return lastTime;
  89 + }
  90 +
  91 + public void setLastTime(Instant lastTime) {
  92 + this.lastTime = lastTime;
  93 + }
  94 +
  95 + public int getCount() {
  96 + return count;
  97 + }
  98 +
  99 + public void setCount(int count) {
  100 + this.count = count;
  101 + }
  102 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.bean;
2   -
3   -
4   -import com.genersoft.iot.vmp.utils.DateUtil;
5   -import io.swagger.v3.oas.annotations.media.Schema;
6   -import org.jetbrains.annotations.NotNull;
7   -
8   -import java.time.Instant;
9   -import java.time.temporal.TemporalAccessor;
10   -
11   -/**
12   - * @description:设备录像bean
13   - * @author: swwheihei
14   - * @date: 2020年5月8日 下午2:06:54
15   - */
16   -@Schema(description = "设备录像详情")
17   -public class RecordItem implements Comparable<RecordItem>{
18   -
19   - @Schema(description = "设备编号")
20   - private String deviceId;
21   -
22   - @Schema(description = "名称")
23   - private String name;
24   -
25   - @Schema(description = "文件路径名 (可选)")
26   - private String filePath;
27   -
28   - @Schema(description = "录像文件大小,单位:Byte(可选)")
29   - private String fileSize;
30   -
31   - @Schema(description = "录像地址(可选)")
32   - private String address;
33   -
34   - @Schema(description = "录像开始时间(可选)")
35   - private String startTime;
36   -
37   - @Schema(description = "录像结束时间(可选)")
38   - private String endTime;
39   -
40   - @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密")
41   - private int secrecy;
42   -
43   - @Schema(description = "录像产生类型(可选)time或alarm 或 manua")
44   - private String type;
45   -
46   - @Schema(description = "录像触发者ID(可选)")
47   - private String recorderId;
48   -
49   - public String getDeviceId() {
50   - return deviceId;
51   - }
52   -
53   - public void setDeviceId(String deviceId) {
54   - this.deviceId = deviceId;
55   - }
56   -
57   - public String getName() {
58   - return name;
59   - }
60   -
61   - public void setName(String name) {
62   - this.name = name;
63   - }
64   -
65   - public String getFilePath() {
66   - return filePath;
67   - }
68   -
69   - public void setFilePath(String filePath) {
70   - this.filePath = filePath;
71   - }
72   -
73   - public String getAddress() {
74   - return address;
75   - }
76   -
77   - public void setAddress(String address) {
78   - this.address = address;
79   - }
80   -
81   - public String getStartTime() {
82   - return startTime;
83   - }
84   -
85   - public void setStartTime(String startTime) {
86   - this.startTime = startTime;
87   - }
88   -
89   - public String getEndTime() {
90   - return endTime;
91   - }
92   -
93   - public void setEndTime(String endTime) {
94   - this.endTime = endTime;
95   - }
96   -
97   - public int getSecrecy() {
98   - return secrecy;
99   - }
100   -
101   - public void setSecrecy(int secrecy) {
102   - this.secrecy = secrecy;
103   - }
104   -
105   - public String getType() {
106   - return type;
107   - }
108   -
109   - public void setType(String type) {
110   - this.type = type;
111   - }
112   -
113   - public String getRecorderId() {
114   - return recorderId;
115   - }
116   -
117   - public void setRecorderId(String recorderId) {
118   - this.recorderId = recorderId;
119   - }
120   -
121   - public String getFileSize() {
122   - return fileSize;
123   - }
124   -
125   - public void setFileSize(String fileSize) {
126   - this.fileSize = fileSize;
127   - }
128   -
129   - @Override
130   - public int compareTo(@NotNull RecordItem recordItem) {
131   - TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime);
132   - TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime());
133   - Instant startTimeParamInstant = Instant.from(startTimeParam);
134   - Instant startTimeNowInstant = Instant.from(startTimeNow);
135   - if (startTimeNowInstant.equals(startTimeParamInstant)) {
136   - return 0;
137   - }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) {
138   - return -1;
139   - }else {
140   - return 1;
141   - }
142   -
143   - }
144   -}
  1 +package com.genersoft.iot.vmp.gb28181.bean;
  2 +
  3 +
  4 +import com.genersoft.iot.vmp.utils.DateUtil;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import org.jetbrains.annotations.NotNull;
  7 +
  8 +import java.time.Instant;
  9 +import java.time.temporal.TemporalAccessor;
  10 +
  11 +/**
  12 + * @description:设备录像bean
  13 + * @author: swwheihei
  14 + * @date: 2020年5月8日 下午2:06:54
  15 + */
  16 +@Schema(description = "设备录像详情")
  17 +public class RecordItem implements Comparable<RecordItem>{
  18 +
  19 + @Schema(description = "设备编号")
  20 + private String deviceId;
  21 +
  22 + @Schema(description = "名称")
  23 + private String name;
  24 +
  25 + @Schema(description = "文件路径名 (可选)")
  26 + private String filePath;
  27 +
  28 + @Schema(description = "录像文件大小,单位:Byte(可选)")
  29 + private String fileSize;
  30 +
  31 + @Schema(description = "录像地址(可选)")
  32 + private String address;
  33 +
  34 + @Schema(description = "录像开始时间(可选)")
  35 + private String startTime;
  36 +
  37 + @Schema(description = "录像结束时间(可选)")
  38 + private String endTime;
  39 +
  40 + @Schema(description = "保密属性(必选)缺省为0;0:不涉密,1:涉密")
  41 + private int secrecy;
  42 +
  43 + @Schema(description = "录像产生类型(可选)time或alarm 或 manua")
  44 + private String type;
  45 +
  46 + @Schema(description = "录像触发者ID(可选)")
  47 + private String recorderId;
  48 +
  49 + public String getDeviceId() {
  50 + return deviceId;
  51 + }
  52 +
  53 + public void setDeviceId(String deviceId) {
  54 + this.deviceId = deviceId;
  55 + }
  56 +
  57 + public String getName() {
  58 + return name;
  59 + }
  60 +
  61 + public void setName(String name) {
  62 + this.name = name;
  63 + }
  64 +
  65 + public String getFilePath() {
  66 + return filePath;
  67 + }
  68 +
  69 + public void setFilePath(String filePath) {
  70 + this.filePath = filePath;
  71 + }
  72 +
  73 + public String getAddress() {
  74 + return address;
  75 + }
  76 +
  77 + public void setAddress(String address) {
  78 + this.address = address;
  79 + }
  80 +
  81 + public String getStartTime() {
  82 + return startTime;
  83 + }
  84 +
  85 + public void setStartTime(String startTime) {
  86 + this.startTime = startTime;
  87 + }
  88 +
  89 + public String getEndTime() {
  90 + return endTime;
  91 + }
  92 +
  93 + public void setEndTime(String endTime) {
  94 + this.endTime = endTime;
  95 + }
  96 +
  97 + public int getSecrecy() {
  98 + return secrecy;
  99 + }
  100 +
  101 + public void setSecrecy(int secrecy) {
  102 + this.secrecy = secrecy;
  103 + }
  104 +
  105 + public String getType() {
  106 + return type;
  107 + }
  108 +
  109 + public void setType(String type) {
  110 + this.type = type;
  111 + }
  112 +
  113 + public String getRecorderId() {
  114 + return recorderId;
  115 + }
  116 +
  117 + public void setRecorderId(String recorderId) {
  118 + this.recorderId = recorderId;
  119 + }
  120 +
  121 + public String getFileSize() {
  122 + return fileSize;
  123 + }
  124 +
  125 + public void setFileSize(String fileSize) {
  126 + this.fileSize = fileSize;
  127 + }
  128 +
  129 + @Override
  130 + public int compareTo(@NotNull RecordItem recordItem) {
  131 + TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime);
  132 + TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime());
  133 + Instant startTimeParamInstant = Instant.from(startTimeParam);
  134 + Instant startTimeNowInstant = Instant.from(startTimeNow);
  135 + if (startTimeNowInstant.equals(startTimeParamInstant)) {
  136 + return 0;
  137 + }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) {
  138 + return -1;
  139 + }else {
  140 + return 1;
  141 + }
  142 +
  143 + }
  144 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RemoteAddressInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SDPInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SendRtpItem.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipMsgInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipTransactionInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java 100644 → 100755
... ... @@ -2,12 +2,9 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3 import com.genersoft.iot.vmp.common.VideoManagerConstants;
4 4 import com.genersoft.iot.vmp.conf.DynamicTask;
  5 +import com.genersoft.iot.vmp.conf.UserSetting;
5 6 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
6 7 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeHandlerTask;
7   -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
8   -import com.genersoft.iot.vmp.service.IPlatformService;
9   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
11 8 import org.springframework.beans.factory.annotation.Autowired;
12 9 import org.springframework.stereotype.Component;
13 10  
... ... @@ -24,6 +21,9 @@ public class SubscribeHolder {
24 21 @Autowired
25 22 private DynamicTask dynamicTask;
26 23  
  24 + @Autowired
  25 + private UserSetting userSetting;
  26 +
27 27 private final String taskOverduePrefix = "subscribe_overdue_";
28 28  
29 29 private static ConcurrentHashMap<String, SubscribeInfo> catalogMap = new ConcurrentHashMap<>();
... ... @@ -58,7 +58,7 @@ public class SubscribeHolder {
58 58  
59 59 public void putMobilePositionSubscribe(String platformId, SubscribeInfo subscribeInfo) {
60 60 mobilePositionMap.put(platformId, subscribeInfo);
61   - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
  61 + String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId;
62 62 // 添加任务处理GPS定时推送
63 63 dynamicTask.startCron(key, new MobilePositionSubscribeHandlerTask(platformId),
64 64 subscribeInfo.getGpsInterval() * 1000);
... ... @@ -76,7 +76,7 @@ public class SubscribeHolder {
76 76  
77 77 public void removeMobilePositionSubscribe(String platformId) {
78 78 mobilePositionMap.remove(platformId);
79   - String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + "MobilePosition_" + platformId;
  79 + String key = VideoManagerConstants.SIP_SUBSCRIBE_PREFIX + userSetting.getServerId() + "MobilePosition_" + platformId;
80 80 // 结束任务处理GPS定时推送
81 81 dynamicTask.stop(key);
82 82 String taskOverdueKey = taskOverduePrefix + "MobilePosition_" + platformId;
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SyncStatus.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/DefaultProperties.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/ServerLoggerImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/conf/StackLoggerImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.event;
2   -
3   -import com.genersoft.iot.vmp.gb28181.bean.*;
4   -import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
5   -import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
6   -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
7   -import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
8   -import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
9   -import org.springframework.beans.factory.annotation.Autowired;
10   -import org.springframework.context.ApplicationEventPublisher;
11   -import org.springframework.stereotype.Component;
12   -
13   -import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
14   -
15   -import javax.sip.TimeoutEvent;
16   -import java.util.ArrayList;
17   -import java.util.HashSet;
18   -import java.util.List;
19   -import java.util.Set;
20   -
21   -/**
22   - * @description:Event事件通知推送器,支持推送在线事件、离线事件
23   - * @author: swwheihei
24   - * @date: 2020年5月6日 上午11:30:50
25   - */
26   -@Component
27   -public class EventPublisher {
28   -
29   - @Autowired
30   - private ApplicationEventPublisher applicationEventPublisher;
31   -
32   - /**
33   - * 设备报警事件
34   - * @param deviceAlarm
35   - */
36   - public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) {
37   - AlarmEvent alarmEvent = new AlarmEvent(this);
38   - alarmEvent.setAlarmInfo(deviceAlarm);
39   - applicationEventPublisher.publishEvent(alarmEvent);
40   - }
41   -
42   - public void zlmOfflineEventPublish(String mediaServerId){
43   - ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this);
44   - outEvent.setMediaServerId(mediaServerId);
45   - applicationEventPublisher.publishEvent(outEvent);
46   - }
47   -
48   - public void zlmOnlineEventPublish(String mediaServerId) {
49   - ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this);
50   - outEvent.setMediaServerId(mediaServerId);
51   - applicationEventPublisher.publishEvent(outEvent);
52   - }
53   -
54   -
55   - public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) {
56   - List<DeviceChannel> deviceChannelList = new ArrayList<>();
57   - deviceChannelList.add(deviceChannel);
58   - catalogEventPublish(platformId, deviceChannelList, type);
59   - }
60   -
61   -
62   - public void requestTimeOut(TimeoutEvent timeoutEvent) {
63   - RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this);
64   - requestTimeoutEvent.setTimeoutEvent(timeoutEvent);
65   - applicationEventPublisher.publishEvent(requestTimeoutEvent);
66   - }
67   -
68   -
69   - /**
70   - *
71   - * @param platformId
72   - * @param deviceChannels
73   - * @param type
74   - */
75   - public void catalogEventPublish(String platformId, List<DeviceChannel> deviceChannels, String type) {
76   - CatalogEvent outEvent = new CatalogEvent(this);
77   - List<DeviceChannel> channels = new ArrayList<>();
78   - if (deviceChannels.size() > 1) {
79   - // 数据去重
80   - Set<String> gbIdSet = new HashSet<>();
81   - for (DeviceChannel deviceChannel : deviceChannels) {
82   - if (!gbIdSet.contains(deviceChannel.getChannelId())) {
83   - gbIdSet.add(deviceChannel.getChannelId());
84   - channels.add(deviceChannel);
85   - }
86   - }
87   - }else {
88   - channels = deviceChannels;
89   - }
90   - outEvent.setDeviceChannels(channels);
91   - outEvent.setType(type);
92   - outEvent.setPlatformId(platformId);
93   - applicationEventPublisher.publishEvent(outEvent);
94   - }
95   -
96   -
97   - public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) {
98   - CatalogEvent outEvent = new CatalogEvent(this);
99   - outEvent.setGbStreams(gbStreams);
100   - outEvent.setType(type);
101   - outEvent.setPlatformId(platformId);
102   - applicationEventPublisher.publishEvent(outEvent);
103   - }
104   -
105   -
106   - public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) {
107   - List<GbStream> gbStreamList = new ArrayList<>();
108   - gbStreamList.add(gbStream);
109   - catalogEventPublishForStream(platformId, gbStreamList, type);
110   - }
111   -
112   - public void recordEndEventPush(RecordInfo recordInfo) {
113   - RecordEndEvent outEvent = new RecordEndEvent(this);
114   - outEvent.setRecordInfo(recordInfo);
115   - applicationEventPublisher.publishEvent(outEvent);
116   - }
117   -
118   -}
  1 +package com.genersoft.iot.vmp.gb28181.event;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.*;
  4 +import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent;
  5 +import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent;
  6 +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  7 +import com.genersoft.iot.vmp.media.zlm.event.ZLMOfflineEvent;
  8 +import com.genersoft.iot.vmp.media.zlm.event.ZLMOnlineEvent;
  9 +import org.springframework.beans.factory.annotation.Autowired;
  10 +import org.springframework.context.ApplicationEventPublisher;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent;
  14 +
  15 +import javax.sip.TimeoutEvent;
  16 +import java.util.ArrayList;
  17 +import java.util.HashSet;
  18 +import java.util.List;
  19 +import java.util.Set;
  20 +
  21 +/**
  22 + * @description:Event事件通知推送器,支持推送在线事件、离线事件
  23 + * @author: swwheihei
  24 + * @date: 2020年5月6日 上午11:30:50
  25 + */
  26 +@Component
  27 +public class EventPublisher {
  28 +
  29 + @Autowired
  30 + private ApplicationEventPublisher applicationEventPublisher;
  31 +
  32 + /**
  33 + * 设备报警事件
  34 + * @param deviceAlarm
  35 + */
  36 + public void deviceAlarmEventPublish(DeviceAlarm deviceAlarm) {
  37 + AlarmEvent alarmEvent = new AlarmEvent(this);
  38 + alarmEvent.setAlarmInfo(deviceAlarm);
  39 + applicationEventPublisher.publishEvent(alarmEvent);
  40 + }
  41 +
  42 + public void zlmOfflineEventPublish(String mediaServerId){
  43 + ZLMOfflineEvent outEvent = new ZLMOfflineEvent(this);
  44 + outEvent.setMediaServerId(mediaServerId);
  45 + applicationEventPublisher.publishEvent(outEvent);
  46 + }
  47 +
  48 + public void zlmOnlineEventPublish(String mediaServerId) {
  49 + ZLMOnlineEvent outEvent = new ZLMOnlineEvent(this);
  50 + outEvent.setMediaServerId(mediaServerId);
  51 + applicationEventPublisher.publishEvent(outEvent);
  52 + }
  53 +
  54 +
  55 + public void catalogEventPublish(String platformId, DeviceChannel deviceChannel, String type) {
  56 + List<DeviceChannel> deviceChannelList = new ArrayList<>();
  57 + deviceChannelList.add(deviceChannel);
  58 + catalogEventPublish(platformId, deviceChannelList, type);
  59 + }
  60 +
  61 +
  62 + public void requestTimeOut(TimeoutEvent timeoutEvent) {
  63 + RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this);
  64 + requestTimeoutEvent.setTimeoutEvent(timeoutEvent);
  65 + applicationEventPublisher.publishEvent(requestTimeoutEvent);
  66 + }
  67 +
  68 +
  69 + /**
  70 + *
  71 + * @param platformId
  72 + * @param deviceChannels
  73 + * @param type
  74 + */
  75 + public void catalogEventPublish(String platformId, List<DeviceChannel> deviceChannels, String type) {
  76 + CatalogEvent outEvent = new CatalogEvent(this);
  77 + List<DeviceChannel> channels = new ArrayList<>();
  78 + if (deviceChannels.size() > 1) {
  79 + // 数据去重
  80 + Set<String> gbIdSet = new HashSet<>();
  81 + for (DeviceChannel deviceChannel : deviceChannels) {
  82 + if (!gbIdSet.contains(deviceChannel.getChannelId())) {
  83 + gbIdSet.add(deviceChannel.getChannelId());
  84 + channels.add(deviceChannel);
  85 + }
  86 + }
  87 + }else {
  88 + channels = deviceChannels;
  89 + }
  90 + outEvent.setDeviceChannels(channels);
  91 + outEvent.setType(type);
  92 + outEvent.setPlatformId(platformId);
  93 + applicationEventPublisher.publishEvent(outEvent);
  94 + }
  95 +
  96 +
  97 + public void catalogEventPublishForStream(String platformId, List<GbStream> gbStreams, String type) {
  98 + CatalogEvent outEvent = new CatalogEvent(this);
  99 + outEvent.setGbStreams(gbStreams);
  100 + outEvent.setType(type);
  101 + outEvent.setPlatformId(platformId);
  102 + applicationEventPublisher.publishEvent(outEvent);
  103 + }
  104 +
  105 +
  106 + public void catalogEventPublishForStream(String platformId, GbStream gbStream, String type) {
  107 + List<GbStream> gbStreamList = new ArrayList<>();
  108 + gbStreamList.add(gbStream);
  109 + catalogEventPublishForStream(platformId, gbStreamList, type);
  110 + }
  111 +
  112 + public void recordEndEventPush(RecordInfo recordInfo) {
  113 + RecordEndEvent outEvent = new RecordEndEvent(this);
  114 + outEvent.setRecordInfo(recordInfo);
  115 + applicationEventPublisher.publishEvent(outEvent);
  116 + }
  117 +
  118 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/alarm/AlarmEventListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/SSRCFactory.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.session;
2   -
3   -import com.genersoft.iot.vmp.common.InviteSessionType;
4   -import com.genersoft.iot.vmp.common.VideoManagerConstants;
5   -import com.genersoft.iot.vmp.conf.UserSetting;
6   -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
7   -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
8   -import com.genersoft.iot.vmp.utils.JsonUtil;
9   -import com.genersoft.iot.vmp.utils.redis.RedisUtil;
10   -import gov.nist.javax.sip.message.SIPResponse;
11   -import org.springframework.beans.factory.annotation.Autowired;
12   -import org.springframework.data.redis.core.RedisTemplate;
13   -import org.springframework.stereotype.Component;
14   -import org.springframework.util.ObjectUtils;
15   -
16   -import java.util.ArrayList;
17   -import java.util.List;
18   -
19   -/**
20   - * 视频流session管理器,管理视频预览、预览回放的通信句柄
21   - */
22   -@Component
23   -public class VideoStreamSessionManager {
24   -
25   - @Autowired
26   - private UserSetting userSetting;
27   -
28   - @Autowired
29   - private RedisTemplate<Object, Object> redisTemplate;
30   -
31   - /**
32   - * 添加一个点播/回放的事务信息
33   - * 后续可以通过流Id/callID
34   - * @param deviceId 设备ID
35   - * @param channelId 通道ID
36   - * @param callId 一次请求的CallID
37   - * @param stream 流名称
38   - * @param mediaServerId 所使用的流媒体ID
39   - * @param response 回复
40   - */
41   - public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){
42   - SsrcTransaction ssrcTransaction = new SsrcTransaction();
43   - ssrcTransaction.setDeviceId(deviceId);
44   - ssrcTransaction.setChannelId(channelId);
45   - ssrcTransaction.setStream(stream);
46   - ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response));
47   - ssrcTransaction.setCallId(callId);
48   - ssrcTransaction.setSsrc(ssrc);
49   - ssrcTransaction.setMediaServerId(mediaServerId);
50   - ssrcTransaction.setType(type);
51   -
52   - redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
53   - + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
54   - }
55   -
56   - public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
57   -
58   - if (ObjectUtils.isEmpty(deviceId)) {
59   - deviceId ="*";
60   - }
61   - if (ObjectUtils.isEmpty(channelId)) {
62   - channelId ="*";
63   - }
64   - if (ObjectUtils.isEmpty(callId)) {
65   - callId ="*";
66   - }
67   - if (ObjectUtils.isEmpty(stream)) {
68   - stream ="*";
69   - }
70   - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
71   - List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
72   - if (scanResult.size() == 0) {
73   - return null;
74   - }
75   - return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0));
76   - }
77   -
78   - public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){
79   - if (ObjectUtils.isEmpty(deviceId)) {
80   - deviceId ="*";
81   - }
82   - if (ObjectUtils.isEmpty(channelId)) {
83   - channelId ="*";
84   - }
85   - if (ObjectUtils.isEmpty(callId)) {
86   - callId ="*";
87   - }
88   - if (ObjectUtils.isEmpty(stream)) {
89   - stream ="*";
90   - }
91   - String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
92   - List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
93   - if (scanResult.size() == 0) {
94   - return null;
95   - }
96   - List<SsrcTransaction> result = new ArrayList<>();
97   - for (Object keyObj : scanResult) {
98   - result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj));
99   - }
100   - return result;
101   - }
102   -
103   - public String getMediaServerId(String deviceId, String channelId, String stream){
104   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
105   - if (ssrcTransaction == null) {
106   - return null;
107   - }
108   - return ssrcTransaction.getMediaServerId();
109   - }
110   -
111   - public String getSSRC(String deviceId, String channelId, String stream){
112   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
113   - if (ssrcTransaction == null) {
114   - return null;
115   - }
116   - return ssrcTransaction.getSsrc();
117   - }
118   -
119   - public void remove(String deviceId, String channelId, String stream) {
120   - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
121   - if (ssrcTransaction == null) {
122   - return;
123   - }
124   - redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_"
125   - + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream());
126   - }
127   -
128   -
129   - public List<SsrcTransaction> getAllSsrc() {
130   - List<Object> ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId()));
131   - List<SsrcTransaction> result= new ArrayList<>();
132   - for (Object ssrcTransactionKey : ssrcTransactionKeys) {
133   - String key = (String) ssrcTransactionKey;
134   - SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class);
135   - result.add(ssrcTransaction);
136   - }
137   - return result;
138   - }
139   -}
  1 +package com.genersoft.iot.vmp.gb28181.session;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
  4 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  5 +import com.genersoft.iot.vmp.conf.UserSetting;
  6 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
  7 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
  8 +import com.genersoft.iot.vmp.utils.JsonUtil;
  9 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  10 +import gov.nist.javax.sip.message.SIPResponse;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.data.redis.core.RedisTemplate;
  13 +import org.springframework.stereotype.Component;
  14 +import org.springframework.util.ObjectUtils;
  15 +
  16 +import java.util.ArrayList;
  17 +import java.util.List;
  18 +
  19 +/**
  20 + * 视频流session管理器,管理视频预览、预览回放的通信句柄
  21 + */
  22 +@Component
  23 +public class VideoStreamSessionManager {
  24 +
  25 + @Autowired
  26 + private UserSetting userSetting;
  27 +
  28 + @Autowired
  29 + private RedisTemplate<Object, Object> redisTemplate;
  30 +
  31 + /**
  32 + * 添加一个点播/回放的事务信息
  33 + * 后续可以通过流Id/callID
  34 + * @param deviceId 设备ID
  35 + * @param channelId 通道ID
  36 + * @param callId 一次请求的CallID
  37 + * @param stream 流名称
  38 + * @param mediaServerId 所使用的流媒体ID
  39 + * @param response 回复
  40 + */
  41 + public void put(String deviceId, String channelId, String callId, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type){
  42 + SsrcTransaction ssrcTransaction = new SsrcTransaction();
  43 + ssrcTransaction.setDeviceId(deviceId);
  44 + ssrcTransaction.setChannelId(channelId);
  45 + ssrcTransaction.setStream(stream);
  46 + ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response));
  47 + ssrcTransaction.setCallId(callId);
  48 + ssrcTransaction.setSsrc(ssrc);
  49 + ssrcTransaction.setMediaServerId(mediaServerId);
  50 + ssrcTransaction.setType(type);
  51 +
  52 + redisTemplate.opsForValue().set(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId()
  53 + + "_" + deviceId + "_" + channelId + "_" + callId + "_" + stream, ssrcTransaction);
  54 + }
  55 +
  56 + public SsrcTransaction getSsrcTransaction(String deviceId, String channelId, String callId, String stream){
  57 +
  58 + if (ObjectUtils.isEmpty(deviceId)) {
  59 + deviceId ="*";
  60 + }
  61 + if (ObjectUtils.isEmpty(channelId)) {
  62 + channelId ="*";
  63 + }
  64 + if (ObjectUtils.isEmpty(callId)) {
  65 + callId ="*";
  66 + }
  67 + if (ObjectUtils.isEmpty(stream)) {
  68 + stream ="*";
  69 + }
  70 + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
  71 + List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
  72 + if (scanResult.size() == 0) {
  73 + return null;
  74 + }
  75 + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0));
  76 + }
  77 +
  78 + public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){
  79 + if (ObjectUtils.isEmpty(deviceId)) {
  80 + deviceId ="*";
  81 + }
  82 + if (ObjectUtils.isEmpty(channelId)) {
  83 + channelId ="*";
  84 + }
  85 + if (ObjectUtils.isEmpty(callId)) {
  86 + callId ="*";
  87 + }
  88 + if (ObjectUtils.isEmpty(stream)) {
  89 + stream ="*";
  90 + }
  91 + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" + deviceId + "_" + channelId + "_" + callId+ "_" + stream;
  92 + List<Object> scanResult = RedisUtil.scan(redisTemplate, key);
  93 + if (scanResult.size() == 0) {
  94 + return null;
  95 + }
  96 + List<SsrcTransaction> result = new ArrayList<>();
  97 + for (Object keyObj : scanResult) {
  98 + result.add((SsrcTransaction)redisTemplate.opsForValue().get(keyObj));
  99 + }
  100 + return result;
  101 + }
  102 +
  103 + public String getMediaServerId(String deviceId, String channelId, String stream){
  104 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
  105 + if (ssrcTransaction == null) {
  106 + return null;
  107 + }
  108 + return ssrcTransaction.getMediaServerId();
  109 + }
  110 +
  111 + public String getSSRC(String deviceId, String channelId, String stream){
  112 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
  113 + if (ssrcTransaction == null) {
  114 + return null;
  115 + }
  116 + return ssrcTransaction.getSsrc();
  117 + }
  118 +
  119 + public void remove(String deviceId, String channelId, String stream) {
  120 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream);
  121 + if (ssrcTransaction == null) {
  122 + return;
  123 + }
  124 + redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_"
  125 + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream());
  126 + }
  127 +
  128 +
  129 + public List<SsrcTransaction> getAllSsrc() {
  130 + List<Object> ssrcTransactionKeys = RedisUtil.scan(redisTemplate, String.format("%s_*_*_*_*", VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX+ userSetting.getServerId()));
  131 + List<SsrcTransaction> result= new ArrayList<>();
  132 + for (Object ssrcTransactionKey : ssrcTransactionKeys) {
  133 + String key = (String) ssrcTransactionKey;
  134 + SsrcTransaction ssrcTransaction = JsonUtil.redisJsonToObject(redisTemplate, key, SsrcTransaction.class);
  135 + result.add(ssrcTransaction);
  136 + }
  137 + return result;
  138 + }
  139 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/ISubscribeTask.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java 100644 → 100755
... ... @@ -12,13 +12,19 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 12 import com.genersoft.iot.vmp.service.IDeviceService;
13 13 import com.genersoft.iot.vmp.service.IMediaServerService;
14 14 import com.genersoft.iot.vmp.service.IPlatformService;
  15 +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
15 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
16 17 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  18 +import org.slf4j.Logger;
  19 +import org.slf4j.LoggerFactory;
17 20 import org.springframework.beans.factory.annotation.Autowired;
18 21 import org.springframework.boot.CommandLineRunner;
19 22 import org.springframework.core.annotation.Order;
20 23 import org.springframework.stereotype.Component;
21 24  
  25 +import javax.sip.InvalidArgumentException;
  26 +import javax.sip.SipException;
  27 +import java.text.ParseException;
22 28 import java.util.HashMap;
23 29 import java.util.List;
24 30 import java.util.Map;
... ... @@ -59,6 +65,8 @@ public class SipRunner implements CommandLineRunner {
59 65 @Autowired
60 66 private ISIPCommanderForPlatform commanderForPlatform;
61 67  
  68 + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
  69 +
62 70 @Override
63 71 public void run(String... args) throws Exception {
64 72 List<Device> deviceList = deviceService.getAllOnlineDevice();
... ... @@ -110,7 +118,11 @@ public class SipRunner implements CommandLineRunner {
110 118 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
111 119 ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
112 120 if (platform != null) {
113   - commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
  121 + try {
  122 + commanderForPlatform.streamByeCmd(platform, sendRtpItem.getCallId());
  123 + } catch (InvalidArgumentException | ParseException | SipException e) {
  124 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  125 + }
114 126 }
115 127 }
116 128 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/CatalogSubscribeTask.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeHandlerTask.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/task/impl/MobilePositionSubscribeTask.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.transmit.callback;
2   -
3   -import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;
4   -import org.springframework.stereotype.Component;
5   -import org.springframework.util.ObjectUtils;
6   -import org.springframework.web.context.request.async.DeferredResult;
7   -
8   -import java.util.Collection;
9   -import java.util.Map;
10   -import java.util.Set;
11   -import java.util.concurrent.ConcurrentHashMap;
12   -
13   -/**
14   - * @description: 异步请求处理
15   - * @author: swwheihei
16   - * @date: 2020年5月8日 下午7:59:05
17   - */
18   -@SuppressWarnings(value = {"rawtypes", "unchecked"})
19   -@Component
20   -public class DeferredResultHolder {
21   -
22   - public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS";
23   -
24   - public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO";
25   -
26   - public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL";
27   -
28   - public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG";
29   -
30   - public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD";
31   -
32   - public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG";
33   -
34   - public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
35   -
36   - public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY";
37   -
38   - public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK";
39   -
40   - public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
41   -
42   - public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
43   -
44   - public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
45   -
46   - public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
47   -
48   - public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
49   -
50   - public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
51   -
52   - public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
53   -
54   - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
55   -
56   - public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP";
57   -
58   - private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();
59   -
60   -
61   - public void put(String key, String id, DeferredResultEx result) {
62   - Map<String, DeferredResultEx> deferredResultMap = map.get(key);
63   - if (deferredResultMap == null) {
64   - deferredResultMap = new ConcurrentHashMap<>();
65   - map.put(key, deferredResultMap);
66   - }
67   - deferredResultMap.put(id, result);
68   - }
69   -
70   - public void put(String key, String id, DeferredResult result) {
71   - Map<String, DeferredResultEx> deferredResultMap = map.get(key);
72   - if (deferredResultMap == null) {
73   - deferredResultMap = new ConcurrentHashMap<>();
74   - map.put(key, deferredResultMap);
75   - }
76   - deferredResultMap.put(id, new DeferredResultEx(result));
77   - }
78   -
79   - public DeferredResultEx get(String key, String id) {
80   - Map<String, DeferredResultEx> deferredResultMap = map.get(key);
81   - if (deferredResultMap == null || ObjectUtils.isEmpty(id)) {
82   - return null;
83   - }
84   - return deferredResultMap.get(id);
85   - }
86   -
87   - public Collection<DeferredResultEx> getAllByKey(String key) {
88   - Map<String, DeferredResultEx> deferredResultMap = map.get(key);
89   - if (deferredResultMap == null) {
90   - return null;
91   - }
92   - return deferredResultMap.values();
93   - }
94   -
95   - public boolean exist(String key, String id){
96   - if (key == null) {
97   - return false;
98   - }
99   - Map<String, DeferredResultEx> deferredResultMap = map.get(key);
100   - if (id == null) {
101   - return deferredResultMap != null;
102   - }else {
103   - return deferredResultMap != null && deferredResultMap.get(id) != null;
104   - }
105   - }
106   -
107   - /**
108   - * 释放单个请求
109   - * @param msg
110   - */
111   - public void invokeResult(RequestMessage msg) {
112   - Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey());
113   - if (deferredResultMap == null) {
114   - return;
115   - }
116   - DeferredResultEx result = deferredResultMap.get(msg.getId());
117   - if (result == null) {
118   - return;
119   - }
120   - result.getDeferredResult().setResult(msg.getData());
121   - deferredResultMap.remove(msg.getId());
122   - if (deferredResultMap.size() == 0) {
123   - map.remove(msg.getKey());
124   - }
125   - }
126   -
127   - /**
128   - * 释放所有的请求
129   - * @param msg
130   - */
131   - public void invokeAllResult(RequestMessage msg) {
132   - Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey());
133   - if (deferredResultMap == null) {
134   - return;
135   - }
136   - synchronized (this) {
137   - deferredResultMap = map.get(msg.getKey());
138   - if (deferredResultMap == null) {
139   - return;
140   - }
141   - Set<String> ids = deferredResultMap.keySet();
142   - for (String id : ids) {
143   - DeferredResultEx result = deferredResultMap.get(id);
144   - if (result == null) {
145   - return;
146   - }
147   - if (result.getFilter() != null) {
148   - Object handler = result.getFilter().handler(msg.getData());
149   - result.getDeferredResult().setResult(handler);
150   - }else {
151   - result.getDeferredResult().setResult(msg.getData());
152   - }
153   -
154   - }
155   - map.remove(msg.getKey());
156   - }
157   - }
158   -
159   -
160   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.callback;
  2 +
  3 +import com.genersoft.iot.vmp.vmanager.bean.DeferredResultEx;
  4 +import org.springframework.stereotype.Component;
  5 +import org.springframework.util.ObjectUtils;
  6 +import org.springframework.web.context.request.async.DeferredResult;
  7 +
  8 +import java.util.Collection;
  9 +import java.util.Map;
  10 +import java.util.Set;
  11 +import java.util.concurrent.ConcurrentHashMap;
  12 +
  13 +/**
  14 + * @description: 异步请求处理
  15 + * @author: swwheihei
  16 + * @date: 2020年5月8日 下午7:59:05
  17 + */
  18 +@SuppressWarnings(value = {"rawtypes", "unchecked"})
  19 +@Component
  20 +public class DeferredResultHolder {
  21 +
  22 + public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS";
  23 +
  24 + public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO";
  25 +
  26 + public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL";
  27 +
  28 + public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG";
  29 +
  30 + public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD";
  31 +
  32 + public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG";
  33 +
  34 + public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO";
  35 +
  36 + public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY";
  37 +
  38 + public static final String CALLBACK_CMD_PLAYBACK = "CALLBACK_PLAYBACK";
  39 +
  40 + public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD";
  41 +
  42 + public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY";
  43 +
  44 + public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
  45 +
  46 + public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL";
  47 +
  48 + public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION";
  49 +
  50 + public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY";
  51 +
  52 + public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM";
  53 +
  54 + public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST";
  55 +
  56 + public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP";
  57 +
  58 + private Map<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();
  59 +
  60 +
  61 + public void put(String key, String id, DeferredResultEx result) {
  62 + Map<String, DeferredResultEx> deferredResultMap = map.get(key);
  63 + if (deferredResultMap == null) {
  64 + deferredResultMap = new ConcurrentHashMap<>();
  65 + map.put(key, deferredResultMap);
  66 + }
  67 + deferredResultMap.put(id, result);
  68 + }
  69 +
  70 + public void put(String key, String id, DeferredResult result) {
  71 + Map<String, DeferredResultEx> deferredResultMap = map.get(key);
  72 + if (deferredResultMap == null) {
  73 + deferredResultMap = new ConcurrentHashMap<>();
  74 + map.put(key, deferredResultMap);
  75 + }
  76 + deferredResultMap.put(id, new DeferredResultEx(result));
  77 + }
  78 +
  79 + public DeferredResultEx get(String key, String id) {
  80 + Map<String, DeferredResultEx> deferredResultMap = map.get(key);
  81 + if (deferredResultMap == null || ObjectUtils.isEmpty(id)) {
  82 + return null;
  83 + }
  84 + return deferredResultMap.get(id);
  85 + }
  86 +
  87 + public Collection<DeferredResultEx> getAllByKey(String key) {
  88 + Map<String, DeferredResultEx> deferredResultMap = map.get(key);
  89 + if (deferredResultMap == null) {
  90 + return null;
  91 + }
  92 + return deferredResultMap.values();
  93 + }
  94 +
  95 + public boolean exist(String key, String id){
  96 + if (key == null) {
  97 + return false;
  98 + }
  99 + Map<String, DeferredResultEx> deferredResultMap = map.get(key);
  100 + if (id == null) {
  101 + return deferredResultMap != null;
  102 + }else {
  103 + return deferredResultMap != null && deferredResultMap.get(id) != null;
  104 + }
  105 + }
  106 +
  107 + /**
  108 + * 释放单个请求
  109 + * @param msg
  110 + */
  111 + public void invokeResult(RequestMessage msg) {
  112 + Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey());
  113 + if (deferredResultMap == null) {
  114 + return;
  115 + }
  116 + DeferredResultEx result = deferredResultMap.get(msg.getId());
  117 + if (result == null) {
  118 + return;
  119 + }
  120 + result.getDeferredResult().setResult(msg.getData());
  121 + deferredResultMap.remove(msg.getId());
  122 + if (deferredResultMap.size() == 0) {
  123 + map.remove(msg.getKey());
  124 + }
  125 + }
  126 +
  127 + /**
  128 + * 释放所有的请求
  129 + * @param msg
  130 + */
  131 + public void invokeAllResult(RequestMessage msg) {
  132 + Map<String, DeferredResultEx> deferredResultMap = map.get(msg.getKey());
  133 + if (deferredResultMap == null) {
  134 + return;
  135 + }
  136 + synchronized (this) {
  137 + deferredResultMap = map.get(msg.getKey());
  138 + if (deferredResultMap == null) {
  139 + return;
  140 + }
  141 + Set<String> ids = deferredResultMap.keySet();
  142 + for (String id : ids) {
  143 + DeferredResultEx result = deferredResultMap.get(id);
  144 + if (result == null) {
  145 + return;
  146 + }
  147 + if (result.getFilter() != null) {
  148 + Object handler = result.getFilter().handler(msg.getData());
  149 + result.getDeferredResult().setResult(handler);
  150 + }else {
  151 + result.getDeferredResult().setResult(msg.getData());
  152 + }
  153 +
  154 + }
  155 + map.remove(msg.getKey());
  156 + }
  157 + }
  158 +
  159 +
  160 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/RequestMessage.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.transmit.callback;
2   -
3   -/**
4   - * @description: 请求信息定义
5   - * @author: swwheihei
6   - * @date: 2020年5月8日 下午1:09:18
7   - */
8   -public class RequestMessage {
9   -
10   - private String id;
11   -
12   - private String key;
13   -
14   - private Object data;
15   -
16   - public String getId() {
17   - return id;
18   - }
19   -
20   - public void setId(String id) {
21   - this.id = id;
22   - }
23   -
24   - public void setKey(String key) {
25   - this.key = key;
26   - }
27   -
28   - public String getKey() {
29   - return key;
30   - }
31   -
32   - public Object getData() {
33   - return data;
34   - }
35   -
36   - public void setData(Object data) {
37   - this.data = data;
38   - }
39   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.callback;
  2 +
  3 +/**
  4 + * @description: 请求信息定义
  5 + * @author: swwheihei
  6 + * @date: 2020年5月8日 下午1:09:18
  7 + */
  8 +public class RequestMessage {
  9 +
  10 + private String id;
  11 +
  12 + private String key;
  13 +
  14 + private Object data;
  15 +
  16 + public String getId() {
  17 + return id;
  18 + }
  19 +
  20 + public void setId(String id) {
  21 + this.id = id;
  22 + }
  23 +
  24 + public void setKey(String key) {
  25 + this.key = key;
  26 + }
  27 +
  28 + public String getKey() {
  29 + return key;
  30 + }
  31 +
  32 + public Object getData() {
  33 + return data;
  34 + }
  35 +
  36 + public void setData(Object data) {
  37 + this.data = data;
  38 + }
  39 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2   -
3   -import com.genersoft.iot.vmp.common.StreamInfo;
4   -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
5   -import com.genersoft.iot.vmp.gb28181.bean.*;
6   -import com.genersoft.iot.vmp.gb28181.bean.Device;
7   -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
8   -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
9   -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
10   -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
11   -import com.genersoft.iot.vmp.service.bean.SSRCInfo;
12   -import gov.nist.javax.sip.message.SIPRequest;
13   -
14   -import javax.sip.InvalidArgumentException;
15   -import javax.sip.SipException;
16   -import java.text.ParseException;
17   -
18   -/**
19   - * @description:设备能力接口,用于定义设备的控制、查询能力
20   - * @author: swwheihei
21   - * @date: 2020年5月3日 下午9:16:34
22   - */
23   -public interface ISIPCommander {
24   -
25   - /**
26   - * 云台方向放控制,使用配置文件中的默认镜头移动速度
27   - *
28   - * @param device 控制设备
29   - * @param channelId 预览通道
30   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
31   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
32   - */
33   - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException;
34   -
35   - /**
36   - * 云台方向放控制
37   - *
38   - * @param device 控制设备
39   - * @param channelId 预览通道
40   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
41   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
42   - * @param moveSpeed 镜头移动速度
43   - */
44   - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
45   -
46   - /**
47   - * 云台缩放控制,使用配置文件中的默认镜头缩放速度
48   - *
49   - * @param device 控制设备
50   - * @param channelId 预览通道
51   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
52   - */
53   - void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException;
54   -
55   - /**
56   - * 云台缩放控制
57   - *
58   - * @param device 控制设备
59   - * @param channelId 预览通道
60   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
61   - */
62   - void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
63   -
64   - /**
65   - * 云台控制,支持方向与缩放控制
66   - *
67   - * @param device 控制设备
68   - * @param channelId 预览通道
69   - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
70   - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
71   - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
72   - * @param moveSpeed 镜头移动速度
73   - * @param zoomSpeed 镜头缩放速度
74   - */
75   - void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException;
76   -
77   - /**
78   - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
79   - *
80   - * @param device 控制设备
81   - * @param channelId 预览通道
82   - * @param cmdCode 指令码
83   - * @param parameter1 数据1
84   - * @param parameter2 数据2
85   - * @param combineCode2 组合码2
86   - */
87   - void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException;
88   -
89   - /**
90   - * 前端控制指令(用于转发上级指令)
91   - * @param device 控制设备
92   - * @param channelId 预览通道
93   - * @param cmdString 前端控制指令串
94   - */
95   - void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
96   -
97   - /**
98   - * 请求预览视频流
99   - * @param device 视频设备
100   - * @param channelId 预览通道
101   - */
102   - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
103   -
104   - /**
105   - * 请求回放视频流
106   - *
107   - * @param device 视频设备
108   - * @param channelId 预览通道
109   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
110   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
111   - */
112   - void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
113   -
114   - /**
115   - * 请求历史媒体下载
116   - *
117   - * @param device 视频设备
118   - * @param channelId 预览通道
119   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
120   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
121   - * @param downloadSpeed 下载倍速参数
122   - */
123   - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
124   - String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
125   - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
126   -
127   -
128   - /**
129   - * 视频流停止
130   - */
131   - void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
132   -
133   - void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
134   -
135   -
136   - void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
137   -
138   - void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
139   -
140   - /**
141   - * 回放暂停
142   - */
143   - void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
144   -
145   - /**
146   - * 回放恢复
147   - */
148   - void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
149   -
150   - /**
151   - * 回放拖动播放
152   - */
153   - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException;
154   -
155   - /**
156   - * 回放倍速播放
157   - */
158   - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException;
159   -
160   - /**
161   - * 回放控制
162   - * @param device
163   - * @param streamInfo
164   - * @param content
165   - */
166   - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
167   -
168   -
169   - /**
170   - * /**
171   - * 语音广播
172   - *
173   - * @param device 视频设备
174   - */
175   - void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
176   -
177   - /**
178   - * 音视频录像控制
179   - *
180   - * @param device 视频设备
181   - * @param channelId 预览通道
182   - * @param recordCmdStr 录像命令:Record / StopRecord
183   - */
184   - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
185   -
186   - /**
187   - * 远程启动控制命令
188   - *
189   - * @param device 视频设备
190   - */
191   - void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
192   -
193   - /**
194   - * 报警布防/撤防命令
195   - *
196   - * @param device 视频设备
197   - */
198   - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
199   -
200   - /**
201   - * 报警复位命令
202   - *
203   - * @param device 视频设备
204   - * @param alarmMethod 报警方式(可选)
205   - * @param alarmType 报警类型(可选)
206   - */
207   - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
208   -
209   - /**
210   - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
211   - *
212   - * @param device 视频设备
213   - * @param channelId 预览通道
214   - */
215   - void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
216   -
217   - /**
218   - * 看守位控制命令
219   - *
220   - * @param device 视频设备
221   - * @param channelId 通道id,非通道则是设备本身
222   - * @param enabled 看守位使能:1 = 开启,0 = 关闭
223   - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
224   - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
225   - */
226   - void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
227   -
228   - /**
229   - * 设备配置命令
230   - *
231   - * @param device 视频设备
232   - */
233   - void deviceConfigCmd(Device device);
234   -
235   - /**
236   - * 设备配置命令:basicParam
237   - *
238   - * @param device 视频设备
239   - * @param channelId 通道编码(可选)
240   - * @param name 设备/通道名称(可选)
241   - * @param expiration 注册过期时间(可选)
242   - * @param heartBeatInterval 心跳间隔时间(可选)
243   - * @param heartBeatCount 心跳超时次数(可选)
244   - */
245   - void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
246   -
247   - /**
248   - * 查询设备状态
249   - *
250   - * @param device 视频设备
251   - */
252   - void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
253   -
254   - /**
255   - * 查询设备信息
256   - *
257   - * @param device 视频设备
258   - * @return
259   - */
260   - void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException;
261   -
262   - /**
263   - * 查询目录列表
264   - *
265   - * @param device 视频设备
266   - */
267   - void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException;
268   -
269   - /**
270   - * 查询录像信息
271   - *
272   - * @param device 视频设备
273   - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
274   - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
275   - * @param sn
276   - */
277   - void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
278   -
279   - /**
280   - * 查询报警信息
281   - *
282   - * @param device 视频设备
283   - * @param startPriority 报警起始级别(可选)
284   - * @param endPriority 报警终止级别(可选)
285   - * @param alarmMethod 报警方式条件(可选)
286   - * @param alarmType 报警类型
287   - * @param startTime 报警发生起始时间(可选)
288   - * @param endTime 报警发生终止时间(可选)
289   - * @return true = 命令发送成功
290   - */
291   - void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
292   - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
293   -
294   - /**
295   - * 查询设备配置
296   - *
297   - * @param device 视频设备
298   - * @param channelId 通道编码(可选)
299   - * @param configType 配置类型:
300   - */
301   - void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
302   -
303   - /**
304   - * 查询设备预置位置
305   - *
306   - * @param device 视频设备
307   - */
308   - void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
309   -
310   - /**
311   - * 查询移动设备位置数据
312   - *
313   - * @param device 视频设备
314   - */
315   - void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
316   -
317   - /**
318   - * 订阅、取消订阅移动位置
319   - *
320   - * @param device 视频设备
321   - * @return true = 命令发送成功
322   - */
323   - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
324   -
325   - /**
326   - * 订阅、取消订阅报警信息
327   - * @param device 视频设备
328   - * @param expires 订阅过期时间(0 = 取消订阅)
329   - * @param startPriority 报警起始级别(可选)
330   - * @param endPriority 报警终止级别(可选)
331   - * @param alarmType 报警类型
332   - * @param startTime 报警发生起始时间(可选)
333   - * @param endTime 报警发生终止时间(可选)
334   - * @return true = 命令发送成功
335   - */
336   - void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException;
337   -
338   - /**
339   - * 订阅、取消订阅目录信息
340   - * @param device 视频设备
341   - * @return true = 命令发送成功
342   - */
343   - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
344   -
345   - /**
346   - * 拉框控制命令
347   - *
348   - * @param device 控制设备
349   - * @param channelId 通道id
350   - * @param cmdString 前端控制指令串
351   - */
352   - void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;
353   -
354   -
355   - /**
356   - * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待
357   - * @param device 设备
358   - * @param deviceAlarm 报警信息信息
359   - * @return
360   - */
361   - void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
362   -
363   -
364   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  5 +import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  7 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  8 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  9 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  10 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  11 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  12 +import gov.nist.javax.sip.message.SIPRequest;
  13 +
  14 +import javax.sip.InvalidArgumentException;
  15 +import javax.sip.SipException;
  16 +import java.text.ParseException;
  17 +
  18 +/**
  19 + * @description:设备能力接口,用于定义设备的控制、查询能力
  20 + * @author: swwheihei
  21 + * @date: 2020年5月3日 下午9:16:34
  22 + */
  23 +public interface ISIPCommander {
  24 +
  25 + /**
  26 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  27 + *
  28 + * @param device 控制设备
  29 + * @param channelId 预览通道
  30 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  31 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  32 + */
  33 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException;
  34 +
  35 + /**
  36 + * 云台方向放控制
  37 + *
  38 + * @param device 控制设备
  39 + * @param channelId 预览通道
  40 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  41 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  42 + * @param moveSpeed 镜头移动速度
  43 + */
  44 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
  45 +
  46 + /**
  47 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  48 + *
  49 + * @param device 控制设备
  50 + * @param channelId 预览通道
  51 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  52 + */
  53 + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException;
  54 +
  55 + /**
  56 + * 云台缩放控制
  57 + *
  58 + * @param device 控制设备
  59 + * @param channelId 预览通道
  60 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  61 + */
  62 + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
  63 +
  64 + /**
  65 + * 云台控制,支持方向与缩放控制
  66 + *
  67 + * @param device 控制设备
  68 + * @param channelId 预览通道
  69 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  70 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  71 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  72 + * @param moveSpeed 镜头移动速度
  73 + * @param zoomSpeed 镜头缩放速度
  74 + */
  75 + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException;
  76 +
  77 + /**
  78 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  79 + *
  80 + * @param device 控制设备
  81 + * @param channelId 预览通道
  82 + * @param cmdCode 指令码
  83 + * @param parameter1 数据1
  84 + * @param parameter2 数据2
  85 + * @param combineCode2 组合码2
  86 + */
  87 + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException;
  88 +
  89 + /**
  90 + * 前端控制指令(用于转发上级指令)
  91 + * @param device 控制设备
  92 + * @param channelId 预览通道
  93 + * @param cmdString 前端控制指令串
  94 + */
  95 + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  96 +
  97 + /**
  98 + * 请求预览视频流
  99 + * @param device 视频设备
  100 + * @param channelId 预览通道
  101 + */
  102 + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  103 +
  104 + /**
  105 + * 请求回放视频流
  106 + *
  107 + * @param device 视频设备
  108 + * @param channelId 预览通道
  109 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  110 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  111 + */
  112 + void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInf, Device device, String channelId, String startTime, String endTime,ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  113 +
  114 + /**
  115 + * 请求历史媒体下载
  116 + *
  117 + * @param device 视频设备
  118 + * @param channelId 预览通道
  119 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  120 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  121 + * @param downloadSpeed 下载倍速参数
  122 + */
  123 + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  124 + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
  125 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  126 +
  127 +
  128 + /**
  129 + * 视频流停止
  130 + */
  131 + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  132 +
  133 + void talkStreamCmd(MediaServerItem mediaServerItem, SendRtpItem sendRtpItem, Device device, String channelId, String callId, ZlmHttpHookSubscribe.Event event, ZlmHttpHookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  134 +
  135 +
  136 + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
  137 +
  138 + void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  139 +
  140 + /**
  141 + * 回放暂停
  142 + */
  143 + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
  144 +
  145 + /**
  146 + * 回放恢复
  147 + */
  148 + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
  149 +
  150 + /**
  151 + * 回放拖动播放
  152 + */
  153 + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException;
  154 +
  155 + /**
  156 + * 回放倍速播放
  157 + */
  158 + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException;
  159 +
  160 + /**
  161 + * 回放控制
  162 + * @param device
  163 + * @param streamInfo
  164 + * @param content
  165 + */
  166 + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
  167 +
  168 +
  169 + /**
  170 + * /**
  171 + * 语音广播
  172 + *
  173 + * @param device 视频设备
  174 + */
  175 + void audioBroadcastCmd(Device device, String channelId, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  176 +
  177 + /**
  178 + * 音视频录像控制
  179 + *
  180 + * @param device 视频设备
  181 + * @param channelId 预览通道
  182 + * @param recordCmdStr 录像命令:Record / StopRecord
  183 + */
  184 + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  185 +
  186 + /**
  187 + * 远程启动控制命令
  188 + *
  189 + * @param device 视频设备
  190 + */
  191 + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
  192 +
  193 + /**
  194 + * 报警布防/撤防命令
  195 + *
  196 + * @param device 视频设备
  197 + */
  198 + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  199 +
  200 + /**
  201 + * 报警复位命令
  202 + *
  203 + * @param device 视频设备
  204 + * @param alarmMethod 报警方式(可选)
  205 + * @param alarmType 报警类型(可选)
  206 + */
  207 + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  208 +
  209 + /**
  210 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  211 + *
  212 + * @param device 视频设备
  213 + * @param channelId 预览通道
  214 + */
  215 + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
  216 +
  217 + /**
  218 + * 看守位控制命令
  219 + *
  220 + * @param device 视频设备
  221 + * @param channelId 通道id,非通道则是设备本身
  222 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  223 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  224 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  225 + */
  226 + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  227 +
  228 + /**
  229 + * 设备配置命令
  230 + *
  231 + * @param device 视频设备
  232 + */
  233 + void deviceConfigCmd(Device device);
  234 +
  235 + /**
  236 + * 设备配置命令:basicParam
  237 + *
  238 + * @param device 视频设备
  239 + * @param channelId 通道编码(可选)
  240 + * @param name 设备/通道名称(可选)
  241 + * @param expiration 注册过期时间(可选)
  242 + * @param heartBeatInterval 心跳间隔时间(可选)
  243 + * @param heartBeatCount 心跳超时次数(可选)
  244 + */
  245 + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  246 +
  247 + /**
  248 + * 查询设备状态
  249 + *
  250 + * @param device 视频设备
  251 + */
  252 + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  253 +
  254 + /**
  255 + * 查询设备信息
  256 + *
  257 + * @param device 视频设备
  258 + * @return
  259 + */
  260 + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException;
  261 +
  262 + /**
  263 + * 查询目录列表
  264 + *
  265 + * @param device 视频设备
  266 + */
  267 + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException;
  268 +
  269 + /**
  270 + * 查询录像信息
  271 + *
  272 + * @param device 视频设备
  273 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  274 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  275 + * @param sn
  276 + */
  277 + void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  278 +
  279 + /**
  280 + * 查询报警信息
  281 + *
  282 + * @param device 视频设备
  283 + * @param startPriority 报警起始级别(可选)
  284 + * @param endPriority 报警终止级别(可选)
  285 + * @param alarmMethod 报警方式条件(可选)
  286 + * @param alarmType 报警类型
  287 + * @param startTime 报警发生起始时间(可选)
  288 + * @param endTime 报警发生终止时间(可选)
  289 + * @return true = 命令发送成功
  290 + */
  291 + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
  292 + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  293 +
  294 + /**
  295 + * 查询设备配置
  296 + *
  297 + * @param device 视频设备
  298 + * @param channelId 通道编码(可选)
  299 + * @param configType 配置类型:
  300 + */
  301 + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  302 +
  303 + /**
  304 + * 查询设备预置位置
  305 + *
  306 + * @param device 视频设备
  307 + */
  308 + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  309 +
  310 + /**
  311 + * 查询移动设备位置数据
  312 + *
  313 + * @param device 视频设备
  314 + */
  315 + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  316 +
  317 + /**
  318 + * 订阅、取消订阅移动位置
  319 + *
  320 + * @param device 视频设备
  321 + * @return true = 命令发送成功
  322 + */
  323 + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  324 +
  325 + /**
  326 + * 订阅、取消订阅报警信息
  327 + * @param device 视频设备
  328 + * @param expires 订阅过期时间(0 = 取消订阅)
  329 + * @param startPriority 报警起始级别(可选)
  330 + * @param endPriority 报警终止级别(可选)
  331 + * @param alarmType 报警类型
  332 + * @param startTime 报警发生起始时间(可选)
  333 + * @param endTime 报警发生终止时间(可选)
  334 + * @return true = 命令发送成功
  335 + */
  336 + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException;
  337 +
  338 + /**
  339 + * 订阅、取消订阅目录信息
  340 + * @param device 视频设备
  341 + * @return true = 命令发送成功
  342 + */
  343 + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  344 +
  345 + /**
  346 + * 拉框控制命令
  347 + *
  348 + * @param device 控制设备
  349 + * @param channelId 通道id
  350 + * @param cmdString 前端控制指令串
  351 + */
  352 + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;
  353 +
  354 +
  355 + /**
  356 + * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待
  357 + * @param device 设备
  358 + * @param deviceAlarm 报警信息信息
  359 + * @return
  360 + */
  361 + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
  362 +
  363 +
  364 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java 100644 → 100755
... ... @@ -25,6 +25,8 @@ public interface ISIPCommanderForPlatform {
25 25 void register(ParentPlatform parentPlatform, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
26 26  
27 27 void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws InvalidArgumentException, ParseException, SipException;
  28 +
  29 +
28 30 void register(ParentPlatform parentPlatform, SipTransactionInfo sipTransactionInfo, WWWAuthenticateHeader www, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent, boolean isRegister) throws SipException, InvalidArgumentException, ParseException;
29 31  
30 32 /**
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderPlarformProvider.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/ISIPRequestProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/SIPRequestProcessorParent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/CancelRequestProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java 100644 → 100755
... ... @@ -21,10 +21,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
21 21 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
22 22 import com.genersoft.iot.vmp.media.zlm.dto.*;
23 23 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
24   -import com.genersoft.iot.vmp.service.IMediaServerService;
25   -import com.genersoft.iot.vmp.service.IPlayService;
26   -import com.genersoft.iot.vmp.service.IStreamProxyService;
27   -import com.genersoft.iot.vmp.service.IStreamPushService;
  24 +import com.genersoft.iot.vmp.service.*;
28 25 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
29 26 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
30 27 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
... ... @@ -84,6 +81,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
84 81 private IRedisCatchStorage redisCatchStorage;
85 82  
86 83 @Autowired
  84 + private IInviteStreamService inviteStreamService;
  85 +
  86 + @Autowired
87 87 private SSRCFactory ssrcFactory;
88 88  
89 89 @Autowired
... ... @@ -518,10 +518,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
518 518 errorEvent.run(code, msg, data);
519 519 }
520 520 });
521   - }else {
  521 + } else {
522 522  
523 523 SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> {
524   - if (code == InviteErrorCode.SUCCESS.getCode()){
  524 + if (code == InviteErrorCode.SUCCESS.getCode()) {
525 525 hookEvent.run(code, msg, data);
526 526 } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
527 527 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestProcessor.java 100644 → 100755
... ... @@ -132,7 +132,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
132 132  
133 133 if (CmdType.CATALOG.equals(cmd)) {
134 134 logger.info("接收到Catalog通知");
135   -// processNotifyCatalogList(take.getEvt());
  135 + processNotifyCatalogList(take.getEvt());
136 136 notifyRequestForCatalogProcessor.process(take.getEvt());
137 137 } else if (CmdType.ALARM.equals(cmd)) {
138 138 logger.info("接收到Alarm通知");
... ... @@ -319,6 +319,7 @@ public class NotifyRequestProcessor extends SIPRequestProcessorParent implements
319 319 logger.info("[收到Notify-Alarm]:{}/{}", device.getDeviceId(), deviceAlarm.getChannelId());
320 320 if ("4".equals(deviceAlarm.getAlarmMethod())) {
321 321 MobilePosition mobilePosition = new MobilePosition();
  322 + mobilePosition.setChannelId(channelId);
322 323 mobilePosition.setCreateTime(DateUtil.getNow());
323 324 mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
324 325 mobilePosition.setTime(deviceAlarm.getAlarmTime());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 100644 → 100755
... ... @@ -88,7 +88,11 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
88 88 Response response = null;
89 89 boolean passwordCorrect = false;
90 90 // 注册标志
91   - boolean registerFlag;
  91 + boolean registerFlag = true;
  92 + if (request.getExpires().getExpires() == 0) {
  93 + // 注销成功
  94 + registerFlag = false;
  95 + }
92 96 FromHeader fromHeader = (FromHeader) request.getHeader(FromHeader.NAME);
93 97 AddressImpl address = (AddressImpl) fromHeader.getAddress();
94 98 SipUri uri = (SipUri) address.getURI();
... ... @@ -99,11 +103,12 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
99 103 RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request,
100 104 userSetting.getSipUseSourceIpAsRemoteAddress());
101 105 String requestAddress = remoteAddressInfo.getIp() + ":" + remoteAddressInfo.getPort();
102   - logger.info("[注册请求] 设备:{}, 开始处理: {}", deviceId, requestAddress);
  106 + String title = registerFlag ? "[注册请求]": "[注销请求]";
  107 + logger.info(title + "设备:{}, 开始处理: {}", deviceId, requestAddress);
103 108 if (device != null &&
104 109 device.getSipTransactionInfo() != null &&
105 110 request.getCallIdHeader().getCallId().equals(device.getSipTransactionInfo().getCallId())) {
106   - logger.info("[注册请求] 设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId());
  111 + logger.info(title + "设备:{}, 注册续订: {}",device.getDeviceId(), device.getDeviceId());
107 112 device.setExpires(request.getExpires().getExpires());
108 113 device.setIp(remoteAddressInfo.getIp());
109 114 device.setPort(remoteAddressInfo.getPort());
... ... @@ -123,7 +128,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
123 128 String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword();
124 129 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
125 130 if (authHead == null && !ObjectUtils.isEmpty(password)) {
126   - logger.info("[注册请求] 设备:{}, 回复401: {}",deviceId, requestAddress);
  131 + logger.info(title + " 设备:{}, 回复401: {}",deviceId, requestAddress);
127 132 response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
128 133 new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
129 134 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
... ... @@ -138,7 +143,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
138 143 // 注册失败
139 144 response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
140 145 response.setReasonPhrase("wrong password");
141   - logger.info("[注册请求] 设备:{}, 密码/SIP服务器ID错误, 回复403: {}", deviceId, requestAddress);
  146 + logger.info(title + " 设备:{}, 密码/SIP服务器ID错误, 回复403: {}", deviceId, requestAddress);
142 147 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
143 148 return;
144 149 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/SubscribeRequestProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java 100644 → 100755
1   -package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
2   -
3   -import com.genersoft.iot.vmp.common.InviteInfo;
4   -import com.genersoft.iot.vmp.common.InviteSessionType;
5   -import com.genersoft.iot.vmp.gb28181.bean.*;
6   -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
7   -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
8   -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
9   -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
10   -import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
11   -import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
12   -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
13   -import com.genersoft.iot.vmp.service.IInviteStreamService;
14   -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
15   -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
16   -import gov.nist.javax.sip.message.SIPRequest;
17   -import org.slf4j.Logger;
18   -import org.slf4j.LoggerFactory;
19   -import org.springframework.beans.factory.InitializingBean;
20   -import org.springframework.beans.factory.annotation.Autowired;
21   -import org.springframework.stereotype.Component;
22   -
23   -import javax.sip.InvalidArgumentException;
24   -import javax.sip.RequestEvent;
25   -import javax.sip.SipException;
26   -import javax.sip.header.CallIdHeader;
27   -import javax.sip.header.ContentTypeHeader;
28   -import javax.sip.message.Response;
29   -import java.text.ParseException;
30   -
31   -@Component
32   -public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
33   -
34   - private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class);
35   -
36   - private final String method = "INFO";
37   -
38   - @Autowired
39   - private SIPProcessorObserver sipProcessorObserver;
40   -
41   - @Autowired
42   - private IVideoManagerStorage storage;
43   -
44   - @Autowired
45   - private SipSubscribe sipSubscribe;
46   -
47   - @Autowired
48   - private IRedisCatchStorage redisCatchStorage;
49   -
50   - @Autowired
51   - private IInviteStreamService inviteStreamService;
52   -
53   - @Autowired
54   - private IVideoManagerStorage storager;
55   -
56   - @Autowired
57   - private SIPCommander cmder;
58   -
59   - @Autowired
60   - private VideoStreamSessionManager sessionManager;
61   -
62   - @Override
63   - public void afterPropertiesSet() throws Exception {
64   - // 添加消息处理的订阅
65   - sipProcessorObserver.addRequestProcessor(method, this);
66   - }
67   -
68   - @Override
69   - public void process(RequestEvent evt) {
70   - logger.debug("接收到消息:" + evt.getRequest());
71   - SIPRequest request = (SIPRequest) evt.getRequest();
72   - String deviceId = SipUtils.getUserIdFromFromHeader(request);
73   - CallIdHeader callIdHeader = request.getCallIdHeader();
74   - // 先从会话内查找
75   - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
76   -
77   - // 兼容海康 媒体通知 消息from字段不是设备ID的问题
78   - if (ssrcTransaction != null) {
79   - deviceId = ssrcTransaction.getDeviceId();
80   - }
81   - // 查询设备是否存在
82   - Device device = redisCatchStorage.getDevice(deviceId);
83   - // 查询上级平台是否存在
84   - ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
85   - try {
86   - if (device != null && parentPlatform != null) {
87   - logger.warn("[重复]平台与设备编号重复:{}", deviceId);
88   - String hostAddress = request.getRemoteAddress().getHostAddress();
89   - int remotePort = request.getRemotePort();
90   - if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
91   - parentPlatform = null;
92   - }else {
93   - device = null;
94   - }
95   - }
96   - if (device == null && parentPlatform == null) {
97   - // 不存在则回复404
98   - responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found");
99   - logger.warn("[设备未找到 ]: {}", deviceId);
100   - if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
101   - DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog());
102   - deviceNotFoundEvent.setCallId(callIdHeader.getCallId());
103   - SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent);
104   - sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
105   - };
106   - }else {
107   - ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
108   - String contentType = header.getContentType();
109   - String contentSubType = header.getContentSubType();
110   - if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
111   - SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
112   - String streamId = sendRtpItem.getStream();
113   - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
114   - if (null == inviteInfo) {
115   - responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
116   - return;
117   - }
118   - Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId());
119   - if (inviteInfo.getStreamInfo() != null) {
120   - cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> {
121   - // 失败的回复
122   - try {
123   - responseAck(request, eventResult.statusCode, eventResult.msg);
124   - } catch (SipException | InvalidArgumentException | ParseException e) {
125   - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
126   - }
127   - }, eventResult -> {
128   - // 成功的回复
129   - try {
130   - responseAck(request, eventResult.statusCode);
131   - } catch (SipException | InvalidArgumentException | ParseException e) {
132   - logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
133   - }
134   - });
135   - }
136   -
137   - }
138   - }
139   - } catch (SipException e) {
140   - logger.warn("SIP 回复错误", e);
141   - } catch (InvalidArgumentException e) {
142   - logger.warn("参数无效", e);
143   - } catch (ParseException e) {
144   - logger.warn("SIP回复时解析异常", e);
145   - }
146   - }
147   -
148   -
149   -}
  1 +package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteInfo;
  4 +import com.genersoft.iot.vmp.common.InviteSessionType;
  5 +import com.genersoft.iot.vmp.gb28181.bean.*;
  6 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  7 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  8 +import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
  9 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  10 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor;
  11 +import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
  12 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  13 +import com.genersoft.iot.vmp.service.IInviteStreamService;
  14 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  15 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  16 +import gov.nist.javax.sip.message.SIPRequest;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +import org.springframework.beans.factory.InitializingBean;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.stereotype.Component;
  22 +
  23 +import javax.sip.InvalidArgumentException;
  24 +import javax.sip.RequestEvent;
  25 +import javax.sip.SipException;
  26 +import javax.sip.header.CallIdHeader;
  27 +import javax.sip.header.ContentTypeHeader;
  28 +import javax.sip.message.Response;
  29 +import java.text.ParseException;
  30 +
  31 +@Component
  32 +public class InfoRequestProcessor extends SIPRequestProcessorParent implements InitializingBean, ISIPRequestProcessor {
  33 +
  34 + private final static Logger logger = LoggerFactory.getLogger(InfoRequestProcessor.class);
  35 +
  36 + private final String method = "INFO";
  37 +
  38 + @Autowired
  39 + private SIPProcessorObserver sipProcessorObserver;
  40 +
  41 + @Autowired
  42 + private IVideoManagerStorage storage;
  43 +
  44 + @Autowired
  45 + private SipSubscribe sipSubscribe;
  46 +
  47 + @Autowired
  48 + private IRedisCatchStorage redisCatchStorage;
  49 +
  50 + @Autowired
  51 + private IInviteStreamService inviteStreamService;
  52 +
  53 + @Autowired
  54 + private IVideoManagerStorage storager;
  55 +
  56 + @Autowired
  57 + private SIPCommander cmder;
  58 +
  59 + @Autowired
  60 + private VideoStreamSessionManager sessionManager;
  61 +
  62 + @Override
  63 + public void afterPropertiesSet() throws Exception {
  64 + // 添加消息处理的订阅
  65 + sipProcessorObserver.addRequestProcessor(method, this);
  66 + }
  67 +
  68 + @Override
  69 + public void process(RequestEvent evt) {
  70 + logger.debug("接收到消息:" + evt.getRequest());
  71 + SIPRequest request = (SIPRequest) evt.getRequest();
  72 + String deviceId = SipUtils.getUserIdFromFromHeader(request);
  73 + CallIdHeader callIdHeader = request.getCallIdHeader();
  74 + // 先从会话内查找
  75 + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransaction(null, null, callIdHeader.getCallId(), null);
  76 +
  77 + // 兼容海康 媒体通知 消息from字段不是设备ID的问题
  78 + if (ssrcTransaction != null) {
  79 + deviceId = ssrcTransaction.getDeviceId();
  80 + }
  81 + // 查询设备是否存在
  82 + Device device = redisCatchStorage.getDevice(deviceId);
  83 + // 查询上级平台是否存在
  84 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(deviceId);
  85 + try {
  86 + if (device != null && parentPlatform != null) {
  87 + logger.warn("[重复]平台与设备编号重复:{}", deviceId);
  88 + String hostAddress = request.getRemoteAddress().getHostAddress();
  89 + int remotePort = request.getRemotePort();
  90 + if (device.getHostAddress().equals(hostAddress + ":" + remotePort)) {
  91 + parentPlatform = null;
  92 + }else {
  93 + device = null;
  94 + }
  95 + }
  96 + if (device == null && parentPlatform == null) {
  97 + // 不存在则回复404
  98 + responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found");
  99 + logger.warn("[设备未找到 ]: {}", deviceId);
  100 + if (sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()) != null){
  101 + DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog());
  102 + deviceNotFoundEvent.setCallId(callIdHeader.getCallId());
  103 + SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(deviceNotFoundEvent);
  104 + sipSubscribe.getErrorSubscribe(callIdHeader.getCallId()).response(eventResult);
  105 + };
  106 + }else {
  107 + ContentTypeHeader header = (ContentTypeHeader)evt.getRequest().getHeader(ContentTypeHeader.NAME);
  108 + String contentType = header.getContentType();
  109 + String contentSubType = header.getContentSubType();
  110 + if ("Application".equalsIgnoreCase(contentType) && "MANSRTSP".equalsIgnoreCase(contentSubType)) {
  111 + SendRtpItem sendRtpItem = redisCatchStorage.querySendRTPServer(null, null, null, callIdHeader.getCallId());
  112 + String streamId = sendRtpItem.getStream();
  113 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId);
  114 + if (null == inviteInfo) {
  115 + responseAck(request, Response.NOT_FOUND, "stream " + streamId + " not found");
  116 + return;
  117 + }
  118 + Device device1 = storager.queryVideoDevice(inviteInfo.getDeviceId());
  119 + if (inviteInfo.getStreamInfo() != null) {
  120 + cmder.playbackControlCmd(device1,inviteInfo.getStreamInfo(),new String(evt.getRequest().getRawContent()),eventResult -> {
  121 + // 失败的回复
  122 + try {
  123 + responseAck(request, eventResult.statusCode, eventResult.msg);
  124 + } catch (SipException | InvalidArgumentException | ParseException e) {
  125 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  126 + }
  127 + }, eventResult -> {
  128 + // 成功的回复
  129 + try {
  130 + responseAck(request, eventResult.statusCode);
  131 + } catch (SipException | InvalidArgumentException | ParseException e) {
  132 + logger.error("[命令发送失败] 国标级联 录像控制: {}", e.getMessage());
  133 + }
  134 + });
  135 + }
  136 +
  137 + }
  138 + }
  139 + } catch (SipException e) {
  140 + logger.warn("SIP 回复错误", e);
  141 + } catch (InvalidArgumentException e) {
  142 + logger.warn("参数无效", e);
  143 + } catch (ParseException e) {
  144 + logger.warn("SIP回复时解析异常", e);
  145 + }
  146 + }
  147 +
  148 +
  149 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/IMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageHandlerAbstract.java 100644 → 100755
... ... @@ -3,7 +3,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message;
3 3 import com.genersoft.iot.vmp.gb28181.bean.Device;
4 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 5 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
6   -import gov.nist.javax.sip.message.SIPRequest;
7 6 import org.dom4j.Element;
8 7 import org.slf4j.Logger;
9 8 import org.slf4j.LoggerFactory;
... ... @@ -24,6 +23,9 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
24 23  
25 24 public Map<String, IMessageHandler> messageHandlerMap = new ConcurrentHashMap<>();
26 25  
  26 + @Autowired
  27 + private IVideoManagerStorage storage;
  28 +
27 29 public void addHandler(String cmdType, IMessageHandler messageHandler) {
28 30 messageHandlerMap.put(cmdType, messageHandler);
29 31 }
... ... @@ -40,7 +42,15 @@ public abstract class MessageHandlerAbstract extends SIPRequestProcessorParent i
40 42 return;
41 43 }
42 44 IMessageHandler messageHandler = messageHandlerMap.get(cmd);
  45 +
43 46 if (messageHandler != null) {
  47 + //两个国标平台互相级联时由于上一步判断导致本该在平台处理的消息 放到了设备的处理逻辑
  48 + //所以对目录查询单独做了校验
  49 + if(messageHandler instanceof CatalogQueryMessageHandler){
  50 + ParentPlatform parentPlatform = storage.queryParentPlatByServerGBId(device.getDeviceId());
  51 + messageHandler.handForPlatform(evt, parentPlatform, element);
  52 + return;
  53 + }
44 54 messageHandler.handForDevice(evt, device, element);
45 55 }
46 56 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/ControlMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/NotifyMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/AlarmNotifyMessageHandler.java 100644 → 100755
... ... @@ -137,6 +137,7 @@ public class AlarmNotifyMessageHandler extends SIPRequestProcessorParent impleme
137 137 MobilePosition mobilePosition = new MobilePosition();
138 138 mobilePosition.setCreateTime(DateUtil.getNow());
139 139 mobilePosition.setDeviceId(deviceAlarm.getDeviceId());
  140 + mobilePosition.setChannelId(channelId);
140 141 mobilePosition.setTime(deviceAlarm.getAlarmTime());
141 142 mobilePosition.setLongitude(deviceAlarm.getLongitude());
142 143 mobilePosition.setLatitude(deviceAlarm.getLatitude());
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java 100644 → 100755
... ... @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
13 13 import com.genersoft.iot.vmp.service.IDeviceService;
14 14 import com.genersoft.iot.vmp.utils.DateUtil;
15 15 import gov.nist.javax.sip.message.SIPRequest;
  16 +import org.apache.commons.lang3.ObjectUtils;
16 17 import org.dom4j.Element;
17 18 import org.slf4j.Logger;
18 19 import org.slf4j.LoggerFactory;
... ... @@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
68 69 } catch (SipException | InvalidArgumentException | ParseException e) {
69 70 logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
70 71 }
71   - if (device.getKeepaliveTime() != null && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){
  72 + if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) {
72 73 logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
73 74 return;
74 75 }
... ... @@ -109,7 +110,11 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
109 110  
110 111 @Override
111 112 public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
112   - // 不会收到上级平台的心跳信息
113   -
  113 + // 个别平台保活不回复200OK会判定离线
  114 + try {
  115 + responseAck((SIPRequest) evt.getRequest(), Response.OK);
  116 + } catch (SipException | InvalidArgumentException | ParseException e) {
  117 + logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
  118 + }
114 119 }
115 120 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MobilePositionNotifyMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/QueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/AlarmQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/CatalogQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceStatusQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/BroadcastResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java 100644 → 100755
... ... @@ -30,6 +30,7 @@ import java.util.ArrayList;
30 30 import java.util.Iterator;
31 31 import java.util.List;
32 32 import java.util.concurrent.ConcurrentLinkedQueue;
  33 +import java.util.concurrent.atomic.AtomicBoolean;
33 34  
34 35 /**
35 36 * 目录查询的回复
... ... @@ -61,6 +62,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
61 62  
62 63 @Autowired
63 64 private SipConfig sipConfig;
  65 + private AtomicBoolean processing = new AtomicBoolean(false);
64 66  
65 67 @Override
66 68 public void afterPropertiesSet() throws Exception {
... ... @@ -69,7 +71,6 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
69 71  
70 72 @Override
71 73 public void handForDevice(RequestEvent evt, Device device, Element element) {
72   - boolean isEmpty = taskQueue.isEmpty();
73 74 taskQueue.offer(new HandlerCatchData(evt, device, element));
74 75 // 回复200 OK
75 76 try {
... ... @@ -77,8 +78,8 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
77 78 } catch (SipException | InvalidArgumentException | ParseException e) {
78 79 logger.error("[命令发送失败] 目录查询回复: {}", e.getMessage());
79 80 }
80   - // 如果不为空则说明已经开启消息处理
81   - if (isEmpty) {
  81 + // 已经开启消息处理则跳过
  82 + if (processing.compareAndSet(false, true)) {
82 83 taskExecutor.execute(() -> {
83 84 while (!taskQueue.isEmpty()) {
84 85 // 全局异常捕获,保证下一条可以得到处理
... ... @@ -147,11 +148,12 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp
147 148 }
148 149  
149 150 }
150   - }catch (Exception e) {
  151 + } catch (Exception e) {
151 152 logger.warn("[收到通道] 发现未处理的异常, \r\n{}", evt.getRequest());
152 153 logger.error("[收到通道] 异常内容: ", e);
153 154 }
154 155 }
  156 + processing.set(false);
155 157 });
156 158 }
157 159  
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/MobilePositionResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/ISIPResponseProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/SIPResponseProcessorAbstract.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/ByeResponseProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/CancelResponseProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/InviteResponseProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/response/impl/RegisterResponseProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
1   -package com.genersoft.iot.vmp.gb28181.utils;
2   -
3   -import com.alibaba.fastjson2.JSONArray;
4   -import com.alibaba.fastjson2.JSONObject;
5   -import com.genersoft.iot.vmp.common.CivilCodePo;
6   -import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
7   -import com.genersoft.iot.vmp.gb28181.bean.Device;
8   -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
9   -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
10   -import com.genersoft.iot.vmp.utils.DateUtil;
11   -import org.apache.commons.lang3.math.NumberUtils;
12   -import org.dom4j.Attribute;
13   -import org.dom4j.Document;
14   -import org.dom4j.DocumentException;
15   -import org.dom4j.Element;
16   -import org.dom4j.io.SAXReader;
17   -import org.slf4j.Logger;
18   -import org.slf4j.LoggerFactory;
19   -import org.springframework.util.ObjectUtils;
20   -import org.springframework.util.ReflectionUtils;
21   -
22   -import javax.sip.RequestEvent;
23   -import javax.sip.message.Request;
24   -import java.io.ByteArrayInputStream;
25   -import java.io.StringReader;
26   -import java.lang.reflect.Field;
27   -import java.lang.reflect.InvocationTargetException;
28   -import java.lang.reflect.ParameterizedType;
29   -import java.lang.reflect.Type;
30   -import java.util.*;
31   -
32   -/**
33   - * 基于dom4j的工具包
34   - *
35   - *
36   - */
37   -public class XmlUtil {
38   - /**
39   - * 日志服务
40   - */
41   - private static Logger logger = LoggerFactory.getLogger(XmlUtil.class);
42   -
43   - /**
44   - * 解析XML为Document对象
45   - *
46   - * @param xml 被解析的XMl
47   - *
48   - * @return Document
49   - */
50   - public static Element parseXml(String xml) {
51   - Document document = null;
52   - //
53   - StringReader sr = new StringReader(xml);
54   - SAXReader saxReader = new SAXReader();
55   - try {
56   - document = saxReader.read(sr);
57   - } catch (DocumentException e) {
58   - logger.error("解析失败", e);
59   - }
60   - return null == document ? null : document.getRootElement();
61   - }
62   -
63   - /**
64   - * 获取element对象的text的值
65   - *
66   - * @param em 节点的对象
67   - * @param tag 节点的tag
68   - * @return 节点
69   - */
70   - public static String getText(Element em, String tag) {
71   - if (null == em) {
72   - return null;
73   - }
74   - Element e = em.element(tag);
75   - //
76   - return null == e ? null : e.getText().trim();
77   - }
78   -
79   - /**
80   - * 递归解析xml节点,适用于 多节点数据
81   - *
82   - * @param node node
83   - * @param nodeName nodeName
84   - * @return List<Map<String, Object>>
85   - */
86   - public static List<Map<String, Object>> listNodes(Element node, String nodeName) {
87   - if (null == node) {
88   - return null;
89   - }
90   - // 初始化返回
91   - List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
92   - // 首先获取当前节点的所有属性节点
93   - List<Attribute> list = node.attributes();
94   -
95   - Map<String, Object> map = null;
96   - // 遍历属性节点
97   - for (Attribute attribute : list) {
98   - if (nodeName.equals(node.getName())) {
99   - if (null == map) {
100   - map = new HashMap<String, Object>();
101   - listMap.add(map);
102   - }
103   - // 取到的节点属性放到map中
104   - map.put(attribute.getName(), attribute.getValue());
105   - }
106   -
107   - }
108   - // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称
109   - // 使用递归
110   - Iterator<Element> iterator = node.elementIterator();
111   - while (iterator.hasNext()) {
112   - Element e = iterator.next();
113   - listMap.addAll(listNodes(e, nodeName));
114   - }
115   - return listMap;
116   - }
117   -
118   - /**
119   - * xml转json
120   - *
121   - * @param element
122   - * @param json
123   - */
124   - public static void node2Json(Element element, JSONObject json) {
125   - // 如果是属性
126   - for (Object o : element.attributes()) {
127   - Attribute attr = (Attribute) o;
128   - if (!ObjectUtils.isEmpty(attr.getValue())) {
129   - json.put("@" + attr.getName(), attr.getValue());
130   - }
131   - }
132   - List<Element> chdEl = element.elements();
133   - if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
134   - json.put(element.getName(), element.getText());
135   - }
136   -
137   - for (Element e : chdEl) { // 有子元素
138   - if (!e.elements().isEmpty()) { // 子元素也有子元素
139   - JSONObject chdjson = new JSONObject();
140   - node2Json(e, chdjson);
141   - Object o = json.get(e.getName());
142   - if (o != null) {
143   - JSONArray jsona = null;
144   - if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray
145   - JSONObject jsono = (JSONObject) o;
146   - json.remove(e.getName());
147   - jsona = new JSONArray();
148   - jsona.add(jsono);
149   - jsona.add(chdjson);
150   - }
151   - if (o instanceof JSONArray) {
152   - jsona = (JSONArray) o;
153   - jsona.add(chdjson);
154   - }
155   - json.put(e.getName(), jsona);
156   - } else {
157   - if (!chdjson.isEmpty()) {
158   - json.put(e.getName(), chdjson);
159   - }
160   - }
161   - } else { // 子元素没有子元素
162   - for (Object o : element.attributes()) {
163   - Attribute attr = (Attribute) o;
164   - if (!ObjectUtils.isEmpty(attr.getValue())) {
165   - json.put("@" + attr.getName(), attr.getValue());
166   - }
167   - }
168   - if (!e.getText().isEmpty()) {
169   - json.put(e.getName(), e.getText());
170   - }
171   - }
172   - }
173   - }
174   - public static Element getRootElement(RequestEvent evt) throws DocumentException {
175   -
176   - return getRootElement(evt, "gb2312");
177   - }
178   -
179   - public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
180   - Request request = evt.getRequest();
181   - return getRootElement(request.getRawContent(), charset);
182   - }
183   -
184   - public static Element getRootElement(byte[] content, String charset) throws DocumentException {
185   - if (charset == null) {
186   - charset = "gb2312";
187   - }
188   - SAXReader reader = new SAXReader();
189   - reader.setEncoding(charset);
190   - Document xml = reader.read(new ByteArrayInputStream(content));
191   - return xml.getRootElement();
192   - }
193   -
194   - private enum ChannelType{
195   - CivilCode, BusinessGroup,VirtualOrganization,Other
196   - }
197   -
198   - public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){
199   - DeviceChannel deviceChannel = new DeviceChannel();
200   - deviceChannel.setDeviceId(device.getDeviceId());
201   - Element channdelIdElement = itemDevice.element("DeviceID");
202   - if (channdelIdElement == null) {
203   - logger.warn("解析Catalog消息时发现缺少 DeviceID");
204   - return null;
205   - }
206   - String channelId = channdelIdElement.getTextTrim();
207   - if (ObjectUtils.isEmpty(channelId)) {
208   - logger.warn("解析Catalog消息时发现缺少 DeviceID");
209   - return null;
210   - }
211   - deviceChannel.setChannelId(channelId);
212   - if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) {
213   - // 除了ADD和update情况下需要识别全部内容,
214   - return deviceChannel;
215   - }
216   - Element nameElement = itemDevice.element("Name");
217   - if (nameElement != null) {
218   - deviceChannel.setName(nameElement.getText());
219   - }
220   - if(channelId.length() <= 8) {
221   - deviceChannel.setHasAudio(false);
222   - CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId);
223   - if (parentCode != null) {
224   - deviceChannel.setParentId(parentCode.getCode());
225   - deviceChannel.setCivilCode(parentCode.getCode());
226   - }else {
227   - logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId);
228   - }
229   - deviceChannel.setStatus(true);
230   - return deviceChannel;
231   - }else {
232   - if(channelId.length() != 20) {
233   - logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId);
234   - return null;
235   - }
236   -
237   - int code = Integer.parseInt(channelId.substring(10, 13));
238   - if (code == 136 || code == 137 || code == 138) {
239   - deviceChannel.setHasAudio(true);
240   - }else {
241   - deviceChannel.setHasAudio(false);
242   - }
243   - // 设备厂商
244   - String manufacturer = getText(itemDevice, "Manufacturer");
245   - // 设备型号
246   - String model = getText(itemDevice, "Model");
247   - // 设备归属
248   - String owner = getText(itemDevice, "Owner");
249   - // 行政区域
250   - String civilCode = getText(itemDevice, "CivilCode");
251   - // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织
252   - String businessGroupID = getText(itemDevice, "BusinessGroupID");
253   - // 父设备/区域/系统ID
254   - String parentID = getText(itemDevice, "ParentID");
255   - if (parentID != null && parentID.equalsIgnoreCase("null")) {
256   - parentID = null;
257   - }
258   - // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
259   - String registerWay = getText(itemDevice, "RegisterWay");
260   - // 保密属性(必选)缺省为0;0:不涉密,1:涉密
261   - String secrecy = getText(itemDevice, "Secrecy");
262   - // 安装地址
263   - String address = getText(itemDevice, "Address");
264   -
265   - switch (code){
266   - case 200:
267   - // 系统目录
268   - if (!ObjectUtils.isEmpty(manufacturer)) {
269   - deviceChannel.setManufacture(manufacturer);
270   - }
271   - if (!ObjectUtils.isEmpty(model)) {
272   - deviceChannel.setModel(model);
273   - }
274   - if (!ObjectUtils.isEmpty(owner)) {
275   - deviceChannel.setOwner(owner);
276   - }
277   - if (!ObjectUtils.isEmpty(civilCode)) {
278   - deviceChannel.setCivilCode(civilCode);
279   - deviceChannel.setParentId(civilCode);
280   - }else {
281   - if (!ObjectUtils.isEmpty(parentID)) {
282   - deviceChannel.setParentId(parentID);
283   - }
284   - }
285   - if (!ObjectUtils.isEmpty(address)) {
286   - deviceChannel.setAddress(address);
287   - }
288   - deviceChannel.setStatus(true);
289   - if (!ObjectUtils.isEmpty(registerWay)) {
290   - try {
291   - deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
292   - }catch (NumberFormatException exception) {
293   - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
294   - }
295   - }
296   - if (!ObjectUtils.isEmpty(secrecy)) {
297   - deviceChannel.setSecrecy(secrecy);
298   - }
299   - return deviceChannel;
300   - case 215:
301   - // 业务分组
302   - deviceChannel.setStatus(true);
303   - if (!ObjectUtils.isEmpty(parentID)) {
304   - if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) {
305   - deviceChannel.setParentId(parentID);
306   - }
307   - }else {
308   - logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId");
309   - if (!ObjectUtils.isEmpty(civilCode)) {
310   - deviceChannel.setCivilCode(civilCode);
311   - }
312   - }
313   - break;
314   - case 216:
315   - // 虚拟组织
316   - deviceChannel.setStatus(true);
317   - if (!ObjectUtils.isEmpty(businessGroupID)) {
318   - deviceChannel.setBusinessGroupId(businessGroupID);
319   - }
320   -
321   - if (!ObjectUtils.isEmpty(parentID)) {
322   - if (parentID.contains("/")) {
323   - String[] parentIdArray = parentID.split("/");
324   - parentID = parentIdArray[parentIdArray.length - 1];
325   - }
326   - deviceChannel.setParentId(parentID);
327   - }else {
328   - if (!ObjectUtils.isEmpty(businessGroupID)) {
329   - deviceChannel.setParentId(businessGroupID);
330   - }
331   - }
332   - break;
333   - default:
334   - // 设备目录
335   - if (!ObjectUtils.isEmpty(manufacturer)) {
336   - deviceChannel.setManufacture(manufacturer);
337   - }
338   - if (!ObjectUtils.isEmpty(model)) {
339   - deviceChannel.setModel(model);
340   - }
341   - if (!ObjectUtils.isEmpty(owner)) {
342   - deviceChannel.setOwner(owner);
343   - }
344   - if (!ObjectUtils.isEmpty(civilCode)
345   - && civilCode.length() <= 8
346   - && NumberUtils.isParsable(civilCode)
347   - && civilCode.length()%2 == 0
348   - ) {
349   - deviceChannel.setCivilCode(civilCode);
350   - }
351   - if (!ObjectUtils.isEmpty(businessGroupID)) {
352   - deviceChannel.setBusinessGroupId(businessGroupID);
353   - }
354   -
355   - // 警区
356   - String block = getText(itemDevice, "Block");
357   - if (!ObjectUtils.isEmpty(block)) {
358   - deviceChannel.setBlock(block);
359   - }
360   - if (!ObjectUtils.isEmpty(address)) {
361   - deviceChannel.setAddress(address);
362   - }
363   -
364   - if (!ObjectUtils.isEmpty(secrecy)) {
365   - deviceChannel.setSecrecy(secrecy);
366   - }
367   -
368   - // 当为设备时,是否有子设备(必选)1有,0没有
369   - String parental = getText(itemDevice, "Parental");
370   - if (!ObjectUtils.isEmpty(parental)) {
371   - try {
372   - // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
373   - if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
374   - deviceChannel.setParental(0);
375   - }else {
376   - deviceChannel.setParental(1);
377   - }
378   - }catch (NumberFormatException e) {
379   - logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental);
380   - }
381   - }
382   - // 父设备/区域/系统ID
383   -
384   - if (!ObjectUtils.isEmpty(parentID) ) {
385   - if (parentID.contains("/")) {
386   - String[] parentIdArray = parentID.split("/");
387   - deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]);
388   - }else {
389   - if (parentID.length()%2 == 0) {
390   - deviceChannel.setParentId(parentID);
391   - }else {
392   - logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID);
393   - }
394   - }
395   - }else {
396   - if (!ObjectUtils.isEmpty(businessGroupID)) {
397   - deviceChannel.setParentId(businessGroupID);
398   - }else {
399   - if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) {
400   - deviceChannel.setParentId(deviceChannel.getCivilCode());
401   - }
402   - }
403   - }
404   - // 注册方式
405   - if (!ObjectUtils.isEmpty(registerWay)) {
406   - try {
407   - int registerWayInt = Integer.parseInt(registerWay);
408   - deviceChannel.setRegisterWay(registerWayInt);
409   - }catch (NumberFormatException exception) {
410   - logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
411   - deviceChannel.setRegisterWay(1);
412   - }
413   - }else {
414   - deviceChannel.setRegisterWay(1);
415   - }
416   -
417   - // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式
418   - String safetyWay = getText(itemDevice, "SafetyWay");
419   - if (!ObjectUtils.isEmpty(safetyWay)) {
420   - try {
421   - deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
422   - }catch (NumberFormatException e) {
423   - logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay);
424   - }
425   - }
426   -
427   - // 证书序列号(有证书的设备必选)
428   - String certNum = getText(itemDevice, "CertNum");
429   - if (!ObjectUtils.isEmpty(certNum)) {
430   - deviceChannel.setCertNum(certNum);
431   - }
432   -
433   - // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效
434   - String certifiable = getText(itemDevice, "Certifiable");
435   - if (!ObjectUtils.isEmpty(certifiable)) {
436   - try {
437   - deviceChannel.setCertifiable(Integer.parseInt(certifiable));
438   - }catch (NumberFormatException e) {
439   - logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable);
440   - }
441   - }
442   -
443   - // 无效原因码(有证书且证书无效的设备必选)
444   - String errCode = getText(itemDevice, "ErrCode");
445   - if (!ObjectUtils.isEmpty(errCode)) {
446   - try {
447   - deviceChannel.setErrCode(Integer.parseInt(errCode));
448   - }catch (NumberFormatException e) {
449   - logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode);
450   - }
451   - }
452   -
453   - // 证书终止有效期(有证书的设备必选)
454   - String endTime = getText(itemDevice, "EndTime");
455   - if (!ObjectUtils.isEmpty(endTime)) {
456   - deviceChannel.setEndTime(endTime);
457   - }
458   -
459   -
460   - // 设备/区域/系统IP地址
461   - String ipAddress = getText(itemDevice, "IPAddress");
462   - if (!ObjectUtils.isEmpty(ipAddress)) {
463   - deviceChannel.setIpAddress(ipAddress);
464   - }
465   -
466   - // 设备/区域/系统端口
467   - String port = getText(itemDevice, "Port");
468   - if (!ObjectUtils.isEmpty(port)) {
469   - try {
470   - deviceChannel.setPort(Integer.parseInt(port));
471   - }catch (NumberFormatException e) {
472   - logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port);
473   - }
474   - }
475   -
476   - // 设备口令
477   - String password = getText(itemDevice, "Password");
478   - if (!ObjectUtils.isEmpty(password)) {
479   - deviceChannel.setPassword(password);
480   - }
481   -
482   -
483   - // 设备状态
484   - String status = getText(itemDevice, "Status");
485   - if (status != null) {
486   - // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
487   - if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
488   - deviceChannel.setStatus(true);
489   - }
490   - if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
491   - deviceChannel.setStatus(false);
492   - }
493   - }else {
494   - deviceChannel.setStatus(true);
495   - }
496   -
497   - // 经度
498   - String longitude = getText(itemDevice, "Longitude");
499   - if (NumericUtil.isDouble(longitude)) {
500   - deviceChannel.setLongitude(Double.parseDouble(longitude));
501   - } else {
502   - deviceChannel.setLongitude(0.00);
503   - }
504   -
505   - // 纬度
506   - String latitude = getText(itemDevice, "Latitude");
507   - if (NumericUtil.isDouble(latitude)) {
508   - deviceChannel.setLatitude(Double.parseDouble(latitude));
509   - } else {
510   - deviceChannel.setLatitude(0.00);
511   - }
512   -
513   - deviceChannel.setGpsTime(DateUtil.getNow());
514   -
515   - // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选
516   - String ptzType = getText(itemDevice, "PTZType");
517   - if (ObjectUtils.isEmpty(ptzType)) {
518   - //兼容INFO中的信息
519   - Element info = itemDevice.element("Info");
520   - String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
521   - if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
522   - try {
523   - deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo));
524   - }catch (NumberFormatException e){
525   - logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo);
526   - }
527   - }
528   - } else {
529   - try {
530   - deviceChannel.setPTZType(Integer.parseInt(ptzType));
531   - }catch (NumberFormatException e){
532   - logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType);
533   - }
534   - }
535   -
536   - // TODO 摄像机位置类型扩展。
537   - // 1-省际检查站、
538   - // 2-党政机关、
539   - // 3-车站码头、
540   - // 4-中心广场、
541   - // 5-体育场馆、
542   - // 6-商业中心、
543   - // 7-宗教场所、
544   - // 8-校园周边、
545   - // 9-治安复杂区域、
546   - // 10-交通干线。
547   - // String positionType = getText(itemDevice, "PositionType");
548   -
549   - // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。
550   - // String roomType = getText(itemDevice, "RoomType");
551   - // TODO 摄像机用途属性
552   - // String useType = getText(itemDevice, "UseType");
553   - // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光
554   - // String supplyLightType = getText(itemDevice, "SupplyLightType");
555   - // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。
556   - // String directionType = getText(itemDevice, "DirectionType");
557   - // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定
558   - // String resolution = getText(itemDevice, "Resolution");
559   -
560   - // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4
561   - // String downloadSpeed = getText(itemDevice, "DownloadSpeed");
562   - // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层)
563   - // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode");
564   - // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强
565   - // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode");
566   -
567   -
568   - deviceChannel.setSecrecy(secrecy);
569   - break;
570   - }
571   - }
572   -
573   - return deviceChannel;
574   - }
575   -
576   - /**
577   - * 新增方法支持内部嵌套
578   - *
579   - * @param element xmlElement
580   - * @param clazz 结果类
581   - * @param <T> 泛型
582   - * @return 结果对象
583   - * @throws NoSuchMethodException
584   - * @throws InvocationTargetException
585   - * @throws InstantiationException
586   - * @throws IllegalAccessException
587   - */
588   - public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
589   - Field[] fields = clazz.getDeclaredFields();
590   - T t = clazz.getDeclaredConstructor().newInstance();
591   - for (Field field : fields) {
592   - ReflectionUtils.makeAccessible(field);
593   - MessageElement annotation = field.getAnnotation(MessageElement.class);
594   - if (annotation == null) {
595   - continue;
596   - }
597   - String value = annotation.value();
598   - String subVal = annotation.subVal();
599   - Element element1 = element.element(value);
600   - if (element1 == null) {
601   - continue;
602   - }
603   - if ("".equals(subVal)) {
604   - // 无下级数据
605   - Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType());
606   - Object o = simpleTypeDeal(field.getType(), fieldVal);
607   - ReflectionUtils.setField(field, t, o);
608   - } else {
609   - // 存在下级数据
610   - ArrayList<Object> list = new ArrayList<>();
611   - Type genericType = field.getGenericType();
612   - if (!(genericType instanceof ParameterizedType)) {
613   - continue;
614   - }
615   - Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
616   - for (Element element2 : element1.elements(subVal)) {
617   - list.add(loadElement(element2, aClass));
618   - }
619   - ReflectionUtils.setField(field, t, list);
620   - }
621   - }
622   - return t;
623   - }
624   -
625   - /**
626   - * 简单类型处理
627   - *
628   - * @param tClass
629   - * @param val
630   - * @return
631   - */
632   - private static Object simpleTypeDeal(Class<?> tClass, Object val) {
633   - if (tClass.equals(String.class)) {
634   - return val.toString();
635   - }
636   - if (tClass.equals(Integer.class)) {
637   - return Integer.valueOf(val.toString());
638   - }
639   - if (tClass.equals(Double.class)) {
640   - return Double.valueOf(val.toString());
641   - }
642   - if (tClass.equals(Long.class)) {
643   - return Long.valueOf(val.toString());
644   - }
645   - return val;
646   - }
  1 +package com.genersoft.iot.vmp.gb28181.utils;
  2 +
  3 +import com.alibaba.fastjson2.JSONArray;
  4 +import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.CivilCodePo;
  6 +import com.genersoft.iot.vmp.conf.CivilCodeFileConf;
  7 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  8 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  9 +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  10 +import com.genersoft.iot.vmp.utils.DateUtil;
  11 +import org.apache.commons.lang3.math.NumberUtils;
  12 +import org.dom4j.Attribute;
  13 +import org.dom4j.Document;
  14 +import org.dom4j.DocumentException;
  15 +import org.dom4j.Element;
  16 +import org.dom4j.io.SAXReader;
  17 +import org.slf4j.Logger;
  18 +import org.slf4j.LoggerFactory;
  19 +import org.springframework.util.ObjectUtils;
  20 +import org.springframework.util.ReflectionUtils;
  21 +
  22 +import javax.sip.RequestEvent;
  23 +import javax.sip.message.Request;
  24 +import java.io.ByteArrayInputStream;
  25 +import java.io.StringReader;
  26 +import java.lang.reflect.Field;
  27 +import java.lang.reflect.InvocationTargetException;
  28 +import java.lang.reflect.ParameterizedType;
  29 +import java.lang.reflect.Type;
  30 +import java.util.*;
  31 +
  32 +/**
  33 + * 基于dom4j的工具包
  34 + *
  35 + *
  36 + */
  37 +public class XmlUtil {
  38 + /**
  39 + * 日志服务
  40 + */
  41 + private static Logger logger = LoggerFactory.getLogger(XmlUtil.class);
  42 +
  43 + /**
  44 + * 解析XML为Document对象
  45 + *
  46 + * @param xml 被解析的XMl
  47 + *
  48 + * @return Document
  49 + */
  50 + public static Element parseXml(String xml) {
  51 + Document document = null;
  52 + //
  53 + StringReader sr = new StringReader(xml);
  54 + SAXReader saxReader = new SAXReader();
  55 + try {
  56 + document = saxReader.read(sr);
  57 + } catch (DocumentException e) {
  58 + logger.error("解析失败", e);
  59 + }
  60 + return null == document ? null : document.getRootElement();
  61 + }
  62 +
  63 + /**
  64 + * 获取element对象的text的值
  65 + *
  66 + * @param em 节点的对象
  67 + * @param tag 节点的tag
  68 + * @return 节点
  69 + */
  70 + public static String getText(Element em, String tag) {
  71 + if (null == em) {
  72 + return null;
  73 + }
  74 + Element e = em.element(tag);
  75 + //
  76 + return null == e ? null : e.getText().trim();
  77 + }
  78 +
  79 + /**
  80 + * 递归解析xml节点,适用于 多节点数据
  81 + *
  82 + * @param node node
  83 + * @param nodeName nodeName
  84 + * @return List<Map<String, Object>>
  85 + */
  86 + public static List<Map<String, Object>> listNodes(Element node, String nodeName) {
  87 + if (null == node) {
  88 + return null;
  89 + }
  90 + // 初始化返回
  91 + List<Map<String, Object>> listMap = new ArrayList<Map<String, Object>>();
  92 + // 首先获取当前节点的所有属性节点
  93 + List<Attribute> list = node.attributes();
  94 +
  95 + Map<String, Object> map = null;
  96 + // 遍历属性节点
  97 + for (Attribute attribute : list) {
  98 + if (nodeName.equals(node.getName())) {
  99 + if (null == map) {
  100 + map = new HashMap<String, Object>();
  101 + listMap.add(map);
  102 + }
  103 + // 取到的节点属性放到map中
  104 + map.put(attribute.getName(), attribute.getValue());
  105 + }
  106 +
  107 + }
  108 + // 遍历当前节点下的所有节点 ,nodeName 要解析的节点名称
  109 + // 使用递归
  110 + Iterator<Element> iterator = node.elementIterator();
  111 + while (iterator.hasNext()) {
  112 + Element e = iterator.next();
  113 + listMap.addAll(listNodes(e, nodeName));
  114 + }
  115 + return listMap;
  116 + }
  117 +
  118 + /**
  119 + * xml转json
  120 + *
  121 + * @param element
  122 + * @param json
  123 + */
  124 + public static void node2Json(Element element, JSONObject json) {
  125 + // 如果是属性
  126 + for (Object o : element.attributes()) {
  127 + Attribute attr = (Attribute) o;
  128 + if (!ObjectUtils.isEmpty(attr.getValue())) {
  129 + json.put("@" + attr.getName(), attr.getValue());
  130 + }
  131 + }
  132 + List<Element> chdEl = element.elements();
  133 + if (chdEl.isEmpty() && !ObjectUtils.isEmpty(element.getText())) {// 如果没有子元素,只有一个值
  134 + json.put(element.getName(), element.getText());
  135 + }
  136 +
  137 + for (Element e : chdEl) { // 有子元素
  138 + if (!e.elements().isEmpty()) { // 子元素也有子元素
  139 + JSONObject chdjson = new JSONObject();
  140 + node2Json(e, chdjson);
  141 + Object o = json.get(e.getName());
  142 + if (o != null) {
  143 + JSONArray jsona = null;
  144 + if (o instanceof JSONObject) { // 如果此元素已存在,则转为jsonArray
  145 + JSONObject jsono = (JSONObject) o;
  146 + json.remove(e.getName());
  147 + jsona = new JSONArray();
  148 + jsona.add(jsono);
  149 + jsona.add(chdjson);
  150 + }
  151 + if (o instanceof JSONArray) {
  152 + jsona = (JSONArray) o;
  153 + jsona.add(chdjson);
  154 + }
  155 + json.put(e.getName(), jsona);
  156 + } else {
  157 + if (!chdjson.isEmpty()) {
  158 + json.put(e.getName(), chdjson);
  159 + }
  160 + }
  161 + } else { // 子元素没有子元素
  162 + for (Object o : element.attributes()) {
  163 + Attribute attr = (Attribute) o;
  164 + if (!ObjectUtils.isEmpty(attr.getValue())) {
  165 + json.put("@" + attr.getName(), attr.getValue());
  166 + }
  167 + }
  168 + if (!e.getText().isEmpty()) {
  169 + json.put(e.getName(), e.getText());
  170 + }
  171 + }
  172 + }
  173 + }
  174 + public static Element getRootElement(RequestEvent evt) throws DocumentException {
  175 +
  176 + return getRootElement(evt, "gb2312");
  177 + }
  178 +
  179 + public static Element getRootElement(RequestEvent evt, String charset) throws DocumentException {
  180 + Request request = evt.getRequest();
  181 + return getRootElement(request.getRawContent(), charset);
  182 + }
  183 +
  184 + public static Element getRootElement(byte[] content, String charset) throws DocumentException {
  185 + if (charset == null) {
  186 + charset = "gb2312";
  187 + }
  188 + SAXReader reader = new SAXReader();
  189 + reader.setEncoding(charset);
  190 + Document xml = reader.read(new ByteArrayInputStream(content));
  191 + return xml.getRootElement();
  192 + }
  193 +
  194 + private enum ChannelType{
  195 + CivilCode, BusinessGroup,VirtualOrganization,Other
  196 + }
  197 +
  198 + public static DeviceChannel channelContentHandler(Element itemDevice, Device device, String event, CivilCodeFileConf civilCodeFileConf){
  199 + DeviceChannel deviceChannel = new DeviceChannel();
  200 + deviceChannel.setDeviceId(device.getDeviceId());
  201 + Element channdelIdElement = itemDevice.element("DeviceID");
  202 + if (channdelIdElement == null) {
  203 + logger.warn("解析Catalog消息时发现缺少 DeviceID");
  204 + return null;
  205 + }
  206 + String channelId = channdelIdElement.getTextTrim();
  207 + if (ObjectUtils.isEmpty(channelId)) {
  208 + logger.warn("解析Catalog消息时发现缺少 DeviceID");
  209 + return null;
  210 + }
  211 + deviceChannel.setChannelId(channelId);
  212 + if (event != null && !event.equals(CatalogEvent.ADD) && !event.equals(CatalogEvent.UPDATE)) {
  213 + // 除了ADD和update情况下需要识别全部内容,
  214 + return deviceChannel;
  215 + }
  216 + Element nameElement = itemDevice.element("Name");
  217 + if (nameElement != null) {
  218 + deviceChannel.setName(nameElement.getText());
  219 + }
  220 + if(channelId.length() <= 8) {
  221 + deviceChannel.setHasAudio(false);
  222 + CivilCodePo parentCode = civilCodeFileConf.getParentCode(channelId);
  223 + if (parentCode != null) {
  224 + deviceChannel.setParentId(parentCode.getCode());
  225 + deviceChannel.setCivilCode(parentCode.getCode());
  226 + }else {
  227 + logger.warn("[xml解析] 无法确定行政区划{}的上级行政区划", channelId);
  228 + }
  229 + deviceChannel.setStatus(true);
  230 + return deviceChannel;
  231 + }else {
  232 + if(channelId.length() != 20) {
  233 + logger.warn("[xml解析] 失败,编号不符合国标28181定义: {}", channelId);
  234 + return null;
  235 + }
  236 +
  237 + int code = Integer.parseInt(channelId.substring(10, 13));
  238 + if (code == 136 || code == 137 || code == 138) {
  239 + deviceChannel.setHasAudio(true);
  240 + }else {
  241 + deviceChannel.setHasAudio(false);
  242 + }
  243 + // 设备厂商
  244 + String manufacturer = getText(itemDevice, "Manufacturer");
  245 + // 设备型号
  246 + String model = getText(itemDevice, "Model");
  247 + // 设备归属
  248 + String owner = getText(itemDevice, "Owner");
  249 + // 行政区域
  250 + String civilCode = getText(itemDevice, "CivilCode");
  251 + // 虚拟组织所属的业务分组ID,业务分组根据特定的业务需求制定,一个业务分组包含一组特定的虚拟组织
  252 + String businessGroupID = getText(itemDevice, "BusinessGroupID");
  253 + // 父设备/区域/系统ID
  254 + String parentID = getText(itemDevice, "ParentID");
  255 + if (parentID != null && parentID.equalsIgnoreCase("null")) {
  256 + parentID = null;
  257 + }
  258 + // 注册方式(必选)缺省为1;1:符合IETFRFC3261标准的认证注册模式;2:基于口令的双向认证注册模式;3:基于数字证书的双向认证注册模式
  259 + String registerWay = getText(itemDevice, "RegisterWay");
  260 + // 保密属性(必选)缺省为0;0:不涉密,1:涉密
  261 + String secrecy = getText(itemDevice, "Secrecy");
  262 + // 安装地址
  263 + String address = getText(itemDevice, "Address");
  264 +
  265 + switch (code){
  266 + case 200:
  267 + // 系统目录
  268 + if (!ObjectUtils.isEmpty(manufacturer)) {
  269 + deviceChannel.setManufacture(manufacturer);
  270 + }
  271 + if (!ObjectUtils.isEmpty(model)) {
  272 + deviceChannel.setModel(model);
  273 + }
  274 + if (!ObjectUtils.isEmpty(owner)) {
  275 + deviceChannel.setOwner(owner);
  276 + }
  277 + if (!ObjectUtils.isEmpty(civilCode)) {
  278 + deviceChannel.setCivilCode(civilCode);
  279 + deviceChannel.setParentId(civilCode);
  280 + }else {
  281 + if (!ObjectUtils.isEmpty(parentID)) {
  282 + deviceChannel.setParentId(parentID);
  283 + }
  284 + }
  285 + if (!ObjectUtils.isEmpty(address)) {
  286 + deviceChannel.setAddress(address);
  287 + }
  288 + deviceChannel.setStatus(true);
  289 + if (!ObjectUtils.isEmpty(registerWay)) {
  290 + try {
  291 + deviceChannel.setRegisterWay(Integer.parseInt(registerWay));
  292 + }catch (NumberFormatException exception) {
  293 + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
  294 + }
  295 + }
  296 + if (!ObjectUtils.isEmpty(secrecy)) {
  297 + deviceChannel.setSecrecy(secrecy);
  298 + }
  299 + return deviceChannel;
  300 + case 215:
  301 + // 业务分组
  302 + deviceChannel.setStatus(true);
  303 + if (!ObjectUtils.isEmpty(parentID)) {
  304 + if (!parentID.trim().equalsIgnoreCase(device.getDeviceId())) {
  305 + deviceChannel.setParentId(parentID);
  306 + }
  307 + }else {
  308 + logger.warn("[xml解析] 业务分组数据中缺少关键信息->ParentId");
  309 + if (!ObjectUtils.isEmpty(civilCode)) {
  310 + deviceChannel.setCivilCode(civilCode);
  311 + }
  312 + }
  313 + break;
  314 + case 216:
  315 + // 虚拟组织
  316 + deviceChannel.setStatus(true);
  317 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  318 + deviceChannel.setBusinessGroupId(businessGroupID);
  319 + }
  320 +
  321 + if (!ObjectUtils.isEmpty(parentID)) {
  322 + if (parentID.contains("/")) {
  323 + String[] parentIdArray = parentID.split("/");
  324 + parentID = parentIdArray[parentIdArray.length - 1];
  325 + }
  326 + deviceChannel.setParentId(parentID);
  327 + }else {
  328 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  329 + deviceChannel.setParentId(businessGroupID);
  330 + }
  331 + }
  332 + break;
  333 + default:
  334 + // 设备目录
  335 + if (!ObjectUtils.isEmpty(manufacturer)) {
  336 + deviceChannel.setManufacture(manufacturer);
  337 + }
  338 + if (!ObjectUtils.isEmpty(model)) {
  339 + deviceChannel.setModel(model);
  340 + }
  341 + if (!ObjectUtils.isEmpty(owner)) {
  342 + deviceChannel.setOwner(owner);
  343 + }
  344 + if (!ObjectUtils.isEmpty(civilCode)
  345 + && civilCode.length() <= 8
  346 + && NumberUtils.isParsable(civilCode)
  347 + && civilCode.length()%2 == 0
  348 + ) {
  349 + deviceChannel.setCivilCode(civilCode);
  350 + }
  351 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  352 + deviceChannel.setBusinessGroupId(businessGroupID);
  353 + }
  354 +
  355 + // 警区
  356 + String block = getText(itemDevice, "Block");
  357 + if (!ObjectUtils.isEmpty(block)) {
  358 + deviceChannel.setBlock(block);
  359 + }
  360 + if (!ObjectUtils.isEmpty(address)) {
  361 + deviceChannel.setAddress(address);
  362 + }
  363 +
  364 + if (!ObjectUtils.isEmpty(secrecy)) {
  365 + deviceChannel.setSecrecy(secrecy);
  366 + }
  367 +
  368 + // 当为设备时,是否有子设备(必选)1有,0没有
  369 + String parental = getText(itemDevice, "Parental");
  370 + if (!ObjectUtils.isEmpty(parental)) {
  371 + try {
  372 + // 由于海康会错误的发送65535作为这里的取值,所以这里除非是0否则认为是1
  373 + if (!ObjectUtils.isEmpty(parental) && parental.length() == 1 && Integer.parseInt(parental) == 0) {
  374 + deviceChannel.setParental(0);
  375 + }else {
  376 + deviceChannel.setParental(1);
  377 + }
  378 + }catch (NumberFormatException e) {
  379 + logger.warn("[xml解析] 从通道数据获取 parental失败: {}", parental);
  380 + }
  381 + }
  382 + // 父设备/区域/系统ID
  383 +
  384 + if (!ObjectUtils.isEmpty(parentID) ) {
  385 + if (parentID.contains("/")) {
  386 + String[] parentIdArray = parentID.split("/");
  387 + deviceChannel.setParentId(parentIdArray[parentIdArray.length - 1]);
  388 + }else {
  389 + if (parentID.length()%2 == 0) {
  390 + deviceChannel.setParentId(parentID);
  391 + }else {
  392 + logger.warn("[xml解析] 不规范的parentID:{}, 已舍弃", parentID);
  393 + }
  394 + }
  395 + }else {
  396 + if (!ObjectUtils.isEmpty(businessGroupID)) {
  397 + deviceChannel.setParentId(businessGroupID);
  398 + }else {
  399 + if (!ObjectUtils.isEmpty(deviceChannel.getCivilCode())) {
  400 + deviceChannel.setParentId(deviceChannel.getCivilCode());
  401 + }
  402 + }
  403 + }
  404 + // 注册方式
  405 + if (!ObjectUtils.isEmpty(registerWay)) {
  406 + try {
  407 + int registerWayInt = Integer.parseInt(registerWay);
  408 + deviceChannel.setRegisterWay(registerWayInt);
  409 + }catch (NumberFormatException exception) {
  410 + logger.warn("[xml解析] 从通道数据获取registerWay失败: {}", registerWay);
  411 + deviceChannel.setRegisterWay(1);
  412 + }
  413 + }else {
  414 + deviceChannel.setRegisterWay(1);
  415 + }
  416 +
  417 + // 信令安全模式(可选)缺省为0; 0:不采用;2:S/MIME 签名方式;3:S/MIME加密签名同时采用方式;4:数字摘要方式
  418 + String safetyWay = getText(itemDevice, "SafetyWay");
  419 + if (!ObjectUtils.isEmpty(safetyWay)) {
  420 + try {
  421 + deviceChannel.setSafetyWay(Integer.parseInt(safetyWay));
  422 + }catch (NumberFormatException e) {
  423 + logger.warn("[xml解析] 从通道数据获取 safetyWay失败: {}", safetyWay);
  424 + }
  425 + }
  426 +
  427 + // 证书序列号(有证书的设备必选)
  428 + String certNum = getText(itemDevice, "CertNum");
  429 + if (!ObjectUtils.isEmpty(certNum)) {
  430 + deviceChannel.setCertNum(certNum);
  431 + }
  432 +
  433 + // 证书有效标识(有证书的设备必选)缺省为0;证书有效标识:0:无效 1:有效
  434 + String certifiable = getText(itemDevice, "Certifiable");
  435 + if (!ObjectUtils.isEmpty(certifiable)) {
  436 + try {
  437 + deviceChannel.setCertifiable(Integer.parseInt(certifiable));
  438 + }catch (NumberFormatException e) {
  439 + logger.warn("[xml解析] 从通道数据获取 Certifiable失败: {}", certifiable);
  440 + }
  441 + }
  442 +
  443 + // 无效原因码(有证书且证书无效的设备必选)
  444 + String errCode = getText(itemDevice, "ErrCode");
  445 + if (!ObjectUtils.isEmpty(errCode)) {
  446 + try {
  447 + deviceChannel.setErrCode(Integer.parseInt(errCode));
  448 + }catch (NumberFormatException e) {
  449 + logger.warn("[xml解析] 从通道数据获取 ErrCode失败: {}", errCode);
  450 + }
  451 + }
  452 +
  453 + // 证书终止有效期(有证书的设备必选)
  454 + String endTime = getText(itemDevice, "EndTime");
  455 + if (!ObjectUtils.isEmpty(endTime)) {
  456 + deviceChannel.setEndTime(endTime);
  457 + }
  458 +
  459 +
  460 + // 设备/区域/系统IP地址
  461 + String ipAddress = getText(itemDevice, "IPAddress");
  462 + if (!ObjectUtils.isEmpty(ipAddress)) {
  463 + deviceChannel.setIpAddress(ipAddress);
  464 + }
  465 +
  466 + // 设备/区域/系统端口
  467 + String port = getText(itemDevice, "Port");
  468 + if (!ObjectUtils.isEmpty(port)) {
  469 + try {
  470 + deviceChannel.setPort(Integer.parseInt(port));
  471 + }catch (NumberFormatException e) {
  472 + logger.warn("[xml解析] 从通道数据获取 Port失败: {}", port);
  473 + }
  474 + }
  475 +
  476 + // 设备口令
  477 + String password = getText(itemDevice, "Password");
  478 + if (!ObjectUtils.isEmpty(password)) {
  479 + deviceChannel.setPassword(password);
  480 + }
  481 +
  482 +
  483 + // 设备状态
  484 + String status = getText(itemDevice, "Status");
  485 + if (status != null) {
  486 + // ONLINE OFFLINE HIKVISION DS-7716N-E4 NVR的兼容性处理
  487 + if (status.equals("ON") || status.equals("On") || status.equals("ONLINE") || status.equals("OK")) {
  488 + deviceChannel.setStatus(true);
  489 + }
  490 + if (status.equals("OFF") || status.equals("Off") || status.equals("OFFLINE")) {
  491 + deviceChannel.setStatus(false);
  492 + }
  493 + }else {
  494 + deviceChannel.setStatus(true);
  495 + }
  496 +
  497 + // 经度
  498 + String longitude = getText(itemDevice, "Longitude");
  499 + if (NumericUtil.isDouble(longitude)) {
  500 + deviceChannel.setLongitude(Double.parseDouble(longitude));
  501 + } else {
  502 + deviceChannel.setLongitude(0.00);
  503 + }
  504 +
  505 + // 纬度
  506 + String latitude = getText(itemDevice, "Latitude");
  507 + if (NumericUtil.isDouble(latitude)) {
  508 + deviceChannel.setLatitude(Double.parseDouble(latitude));
  509 + } else {
  510 + deviceChannel.setLatitude(0.00);
  511 + }
  512 +
  513 + deviceChannel.setGpsTime(DateUtil.getNow());
  514 +
  515 + // -摄像机类型扩展,标识摄像机类型:1-球机;2-半球;3-固定枪机;4-遥控枪机。当目录项为摄像机时可选
  516 + String ptzType = getText(itemDevice, "PTZType");
  517 + if (ObjectUtils.isEmpty(ptzType)) {
  518 + //兼容INFO中的信息
  519 + Element info = itemDevice.element("Info");
  520 + String ptzTypeFromInfo = XmlUtil.getText(info, "PTZType");
  521 + if(!ObjectUtils.isEmpty(ptzTypeFromInfo)){
  522 + try {
  523 + deviceChannel.setPTZType(Integer.parseInt(ptzTypeFromInfo));
  524 + }catch (NumberFormatException e){
  525 + logger.warn("[xml解析] 从通道数据info中获取PTZType失败: {}", ptzTypeFromInfo);
  526 + }
  527 + }
  528 + } else {
  529 + try {
  530 + deviceChannel.setPTZType(Integer.parseInt(ptzType));
  531 + }catch (NumberFormatException e){
  532 + logger.warn("[xml解析] 从通道数据中获取PTZType失败: {}", ptzType);
  533 + }
  534 + }
  535 +
  536 + // TODO 摄像机位置类型扩展。
  537 + // 1-省际检查站、
  538 + // 2-党政机关、
  539 + // 3-车站码头、
  540 + // 4-中心广场、
  541 + // 5-体育场馆、
  542 + // 6-商业中心、
  543 + // 7-宗教场所、
  544 + // 8-校园周边、
  545 + // 9-治安复杂区域、
  546 + // 10-交通干线。
  547 + // String positionType = getText(itemDevice, "PositionType");
  548 +
  549 + // TODO 摄像机安装位置室外、室内属性。1-室外、2-室内。
  550 + // String roomType = getText(itemDevice, "RoomType");
  551 + // TODO 摄像机用途属性
  552 + // String useType = getText(itemDevice, "UseType");
  553 + // TODO 摄像机补光属性。1-无补光、2-红外补光、3-白光补光
  554 + // String supplyLightType = getText(itemDevice, "SupplyLightType");
  555 + // TODO 摄像机监视方位属性。1-东、2-西、3-南、4-北、5-东南、6-东北、7-西南、8-西北。
  556 + // String directionType = getText(itemDevice, "DirectionType");
  557 + // TODO 摄像机支持的分辨率,可有多个分辨率值,各个取值间以“/”分隔。分辨率取值参见附录 F中SDPf字段规定
  558 + // String resolution = getText(itemDevice, "Resolution");
  559 +
  560 + // TODO 下载倍速范围(可选),各可选参数以“/”分隔,如设备支持1,2,4倍速下载则应写为“1/2/4
  561 + // String downloadSpeed = getText(itemDevice, "DownloadSpeed");
  562 + // TODO 空域编码能力,取值0:不支持;1:1级增强(1个增强层);2:2级增强(2个增强层);3:3级增强(3个增强层)
  563 + // String svcSpaceSupportMode = getText(itemDevice, "SVCSpaceSupportMode");
  564 + // TODO 时域编码能力,取值0:不支持;1:1级增强;2:2级增强;3:3级增强
  565 + // String svcTimeSupportMode = getText(itemDevice, "SVCTimeSupportMode");
  566 +
  567 +
  568 + deviceChannel.setSecrecy(secrecy);
  569 + break;
  570 + }
  571 + }
  572 +
  573 + return deviceChannel;
  574 + }
  575 +
  576 + /**
  577 + * 新增方法支持内部嵌套
  578 + *
  579 + * @param element xmlElement
  580 + * @param clazz 结果类
  581 + * @param <T> 泛型
  582 + * @return 结果对象
  583 + * @throws NoSuchMethodException
  584 + * @throws InvocationTargetException
  585 + * @throws InstantiationException
  586 + * @throws IllegalAccessException
  587 + */
  588 + public static <T> T loadElement(Element element, Class<T> clazz) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
  589 + Field[] fields = clazz.getDeclaredFields();
  590 + T t = clazz.getDeclaredConstructor().newInstance();
  591 + for (Field field : fields) {
  592 + ReflectionUtils.makeAccessible(field);
  593 + MessageElement annotation = field.getAnnotation(MessageElement.class);
  594 + if (annotation == null) {
  595 + continue;
  596 + }
  597 + String value = annotation.value();
  598 + String subVal = annotation.subVal();
  599 + Element element1 = element.element(value);
  600 + if (element1 == null) {
  601 + continue;
  602 + }
  603 + if ("".equals(subVal)) {
  604 + // 无下级数据
  605 + Object fieldVal = element1.isTextOnly() ? element1.getText() : loadElement(element1, field.getType());
  606 + Object o = simpleTypeDeal(field.getType(), fieldVal);
  607 + ReflectionUtils.setField(field, t, o);
  608 + } else {
  609 + // 存在下级数据
  610 + ArrayList<Object> list = new ArrayList<>();
  611 + Type genericType = field.getGenericType();
  612 + if (!(genericType instanceof ParameterizedType)) {
  613 + continue;
  614 + }
  615 + Class<?> aClass = (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
  616 + for (Element element2 : element1.elements(subVal)) {
  617 + list.add(loadElement(element2, aClass));
  618 + }
  619 + ReflectionUtils.setField(field, t, list);
  620 + }
  621 + }
  622 + return t;
  623 + }
  624 +
  625 + /**
  626 + * 简单类型处理
  627 + *
  628 + * @param tClass
  629 + * @param val
  630 + * @return
  631 + */
  632 + private static Object simpleTypeDeal(Class<?> tClass, Object val) {
  633 + if (tClass.equals(String.class)) {
  634 + return val.toString();
  635 + }
  636 + if (tClass.equals(Integer.class)) {
  637 + return Integer.valueOf(val.toString());
  638 + }
  639 + if (tClass.equals(Double.class)) {
  640 + return Double.valueOf(val.toString());
  641 + }
  642 + if (tClass.equals(Long.class)) {
  643 + return Long.valueOf(val.toString());
  644 + }
  645 + return val;
  646 + }
647 647 }
648 648 \ No newline at end of file
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
... ... @@ -21,6 +21,7 @@ public class AssistRESTfulUtils {
21 21  
22 22 private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class);
23 23  
  24 +
24 25 public interface RequestCallback{
25 26 void run(JSONObject response);
26 27 }
... ... @@ -145,4 +146,25 @@ public class AssistRESTfulUtils {
145 146 return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback);
146 147 }
147 148  
  149 + public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) {
  150 + Map<String, Object> param = new HashMap<>();
  151 + param.put("app", app);
  152 + param.put("stream", stream);
  153 + param.put("year", year);
  154 + param.put("month", month);
  155 + return sendGet(mediaServerItem, "api/record/date/list", param, null);
  156 + }
  157 +
  158 + public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream,
  159 + String startTime, String endTime) {
  160 + Map<String, Object> param = new HashMap<>();
  161 + param.put("app", app);
  162 + param.put("stream", stream);
  163 + param.put("page", page);
  164 + param.put("count", count);
  165 + param.put("startTime", startTime);
  166 + param.put("endTime", endTime);
  167 + return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null);
  168 + }
  169 +
148 170 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/SendRtpPortManager.java 100644 → 100755
... ... @@ -30,7 +30,7 @@ public class SendRtpPortManager {
30 30  
31 31 private final String KEY = "VM_MEDIA_SEND_RTP_PORT_";
32 32  
33   - public int getNextPort(MediaServerItem mediaServer) {
  33 + public synchronized int getNextPort(MediaServerItem mediaServer) {
34 34 if (mediaServer == null) {
35 35 logger.warn("[发送端口管理] 参数错误,mediaServer为NULL");
36 36 return -1;
... ... @@ -50,17 +50,15 @@ public class SendRtpPortManager {
50 50 String sendRtpPortRange = mediaServer.getSendRtpPortRange();
51 51 int startPort;
52 52 int endPort;
53   - if (sendRtpPortRange == null) {
54   - logger.warn("{}未设置发送端口默认值,自动使用40000-50000作为端口范围", mediaServer.getId());
  53 + if (sendRtpPortRange != null) {
55 54 String[] portArray = sendRtpPortRange.split(",");
56 55 if (portArray.length != 2 || !NumberUtils.isParsable(portArray[0]) || !NumberUtils.isParsable(portArray[1])) {
57   - logger.warn("{}发送端口配置格式错误,自动使用40000-50000作为端口范围", mediaServer.getId());
  56 + logger.warn("{}发送端口配置格式错误,自动使用50000-60000作为端口范围", mediaServer.getId());
58 57 startPort = 50000;
59 58 endPort = 60000;
60 59 }else {
61   -
62 60 if ( Integer.parseInt(portArray[1]) - Integer.parseInt(portArray[0]) < 1) {
63   - logger.warn("{}发送端口配置错误,结束端口至少比开始端口大一,自动使用40000-50000作为端口范围", mediaServer.getId());
  61 + logger.warn("{}发送端口配置错误,结束端口至少比开始端口大一,自动使用50000-60000作为端口范围", mediaServer.getId());
64 62 startPort = 50000;
65 63 endPort = 60000;
66 64 }else {
... ... @@ -69,6 +67,7 @@ public class SendRtpPortManager {
69 67 }
70 68 }
71 69 }else {
  70 + logger.warn("{}未设置发送端口默认值,自动使用50000-60000作为端口范围", mediaServer.getId());
72 71 startPort = 50000;
73 72 endPort = 60000;
74 73 }
... ... @@ -76,10 +75,35 @@ public class SendRtpPortManager {
76 75 logger.warn("{}获取redis连接信息失败", mediaServer.getId());
77 76 return -1;
78 77 }
  78 +// RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
  79 +// return redisAtomicInteger.getAndUpdate((current)->{
  80 +// return getPort(current, startPort, endPort, checkPort-> !sendRtpItemMap.containsKey(checkPort));
  81 +// });
  82 + return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
  83 + }
  84 +
  85 + private synchronized int getSendPort(int startPort, int endPort, String sendIndexKey, Map<Integer, SendRtpItem> sendRtpItemMap){
79 86 RedisAtomicInteger redisAtomicInteger = new RedisAtomicInteger(sendIndexKey , redisTemplate.getConnectionFactory());
80   - return redisAtomicInteger.getAndUpdate((current)->{
81   - return getPort(current, startPort, endPort, checkPort-> !sendRtpItemMap.containsKey(checkPort));
82   - });
  87 + if (redisAtomicInteger.get() < startPort) {
  88 + redisAtomicInteger.set(startPort);
  89 + return startPort;
  90 + }else {
  91 + int port = redisAtomicInteger.getAndIncrement();
  92 + if (port > endPort) {
  93 + redisAtomicInteger.set(startPort);
  94 + if (sendRtpItemMap.containsKey(startPort)) {
  95 + return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
  96 + }else {
  97 + return startPort;
  98 + }
  99 + }
  100 + if (sendRtpItemMap.containsKey(port)) {
  101 + return getSendPort(startPort, endPort, sendIndexKey, sendRtpItemMap);
  102 + }else {
  103 + return port;
  104 + }
  105 + }
  106 +
83 107 }
84 108  
85 109 interface CheckPortCallback{
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 100644 → 100755
... ... @@ -30,6 +30,7 @@ import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
30 30 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
31 31 import com.genersoft.iot.vmp.utils.DateUtil;
32 32 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  33 +import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
33 34 import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
34 35 import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
35 36 import org.slf4j.Logger;
... ... @@ -311,7 +312,10 @@ public class ZLMHttpHookListener {
311 312 if (param.getApp().equalsIgnoreCase("rtp")) {
312 313 String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream();
313 314 OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey);
314   - if (otherRtpSendInfo != null) {
  315 +
  316 + String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream();
  317 + OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS);
  318 + if (otherRtpSendInfo != null || otherPsSendInfo != null) {
315 319 result.setEnable_mp4(true);
316 320 }
317 321 }
... ... @@ -696,7 +700,9 @@ public class ZLMHttpHookListener {
696 700 result.onTimeout(() -> {
697 701 logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");
698 702 msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
699   - resultHolder.invokeResult(msg);
  703 + resultHolder.invokeAllResult(msg);
  704 + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, deviceId, channelId);
  705 + storager.stopPlay(deviceId, channelId);
700 706 });
701 707  
702 708 resultHolder.put(key, uuid, result);
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaListManager.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerConfig.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMServerFactory.java 100644 → 100755
... ... @@ -42,7 +42,7 @@ public class ZLMServerFactory {
42 42 * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
43 43 * @return
44 44 */
45   - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
  45 + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean onlyAuto, Boolean reUsePort, Integer tcpMode) {
46 46 int result = -1;
47 47 // 查询此rtp server 是否已经存在
48 48 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId);
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZlmHttpHookSubscribe.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ChannelOnlineEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRtpServerTimeout.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForServerStarted.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForStreamChange.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookType.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/IHookSubscribe.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ServerKeepaliveData.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamAuthorityInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamProxyItem.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/StreamPushItem.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/ZLMRunInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResult.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPlayHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnPublishHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRtpServerTimeoutHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnSendRtpStoppedHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnServerKeepaliveHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNoneReaderHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamNotFoundHookParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OriginType.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMEventAbstract.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOfflineEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMOnlineEvent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceAlarmService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceChannelService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IDeviceService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IGbStreamService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IInviteStreamService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/ILogService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java 100644 → 100755
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 6 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
7 7 import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
8 8 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  9 +import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
9 10  
10 11 import java.util.List;
11 12  
... ... @@ -95,4 +96,14 @@ public interface IMediaServerService {
95 96 * @return
96 97 */
97 98 MediaServerLoad getLoad(MediaServerItem mediaServerItem);
  99 +
  100 + /**
  101 + * 按时间查找录像文件
  102 + */
  103 + List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
  104 +
  105 + /**
  106 + * 查找存在录像文件的时间
  107 + */
  108 + List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
98 109 }
... ...
src/main/java/com/genersoft/iot/vmp/service/IMediaService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlatformChannelService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlatformService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IRoleService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IStreamProxyService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/IUserService.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ErrorCallback.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/GPSMsgInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/InviteErrorCode.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/InviteTimeOutCallback.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MediaServerLoad.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannel.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/MessageForPushChannelResponse.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackCallback.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PlayBackResult.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/PushStreamStatusChangeFromRedisDto.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/RequestPushStreamMsg.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/RequestSendItemMsg.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ResponseSendItemMsg.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/StreamPushItemFromRedis.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/ThirdPartyGB.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsgCmd.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceAlarmServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceChannelServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java 100644 → 100755
... ... @@ -115,6 +115,7 @@ public class DeviceServiceImpl implements IDeviceService {
115 115 inviteStreamService.clearInviteInfo(device.getDeviceId());
116 116 }
117 117 device.setUpdateTime(now);
  118 + device.setKeepaliveTime(now);
118 119 if (device.getKeepaliveIntervalTime() == 0) {
119 120 // 默认心跳间隔60
120 121 device.setKeepaliveIntervalTime(60);
... ... @@ -535,6 +536,13 @@ public class DeviceServiceImpl implements IDeviceService {
535 536 if (!ObjectUtils.isEmpty(device.getSdpIp())) {
536 537 deviceInStore.setSdpIp(device.getSdpIp());
537 538 }
  539 + if (!ObjectUtils.isEmpty(device.getPassword())) {
  540 + deviceInStore.setPassword(device.getPassword());
  541 + }
  542 + if (!ObjectUtils.isEmpty(device.getStreamMode())) {
  543 + deviceInStore.setStreamMode(device.getStreamMode());
  544 + }
  545 +
538 546  
539 547 // 目录订阅相关的信息
540 548 if (device.getSubscribeCycleForCatalog() > 0) {
... ... @@ -568,18 +576,23 @@ public class DeviceServiceImpl implements IDeviceService {
568 576 if (deviceInStore.getGeoCoordSys() != null) {
569 577 // 坐标系变化,需要重新计算GCJ02坐标和WGS84坐标
570 578 if (!deviceInStore.getGeoCoordSys().equals(device.getGeoCoordSys())) {
571   - updateDeviceChannelGeoCoordSys(device);
  579 + deviceInStore.setGeoCoordSys(device.getGeoCoordSys());
  580 + updateDeviceChannelGeoCoordSys(deviceInStore);
572 581 }
573 582 }else {
574   - device.setGeoCoordSys("WGS84");
  583 + deviceInStore.setGeoCoordSys("WGS84");
575 584 }
576 585 if (device.getCharset() == null) {
577   - device.setCharset("GB2312");
  586 + deviceInStore.setCharset("GB2312");
578 587 }
579   -
  588 + //SSRC校验
  589 + deviceInStore.setSsrcCheck(device.isSsrcCheck());
  590 + //作为消息通道
  591 + deviceInStore.setAsMessageChannel(device.isAsMessageChannel());
  592 +
580 593 // 更新redis
581   - redisCatchStorage.updateDevice(device);
582   - deviceMapper.updateCustom(device);
  594 + deviceMapper.updateCustom(deviceInStore);
  595 + redisCatchStorage.removeDevice(deviceInStore.getDeviceId());
583 596 }
584 597  
585 598 @Override
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java 100644 → 100755
... ... @@ -24,23 +24,30 @@ import com.genersoft.iot.vmp.utils.DateUtil;
24 24 import com.genersoft.iot.vmp.utils.JsonUtil;
25 25 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
26 26 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  27 +import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
27 28 import okhttp3.OkHttpClient;
28 29 import okhttp3.Request;
29 30 import okhttp3.Response;
30 31 import org.slf4j.Logger;
31 32 import org.slf4j.LoggerFactory;
32 33 import org.springframework.beans.factory.annotation.Autowired;
  34 +import org.springframework.beans.factory.annotation.Qualifier;
33 35 import org.springframework.beans.factory.annotation.Value;
34 36 import org.springframework.data.redis.core.RedisTemplate;
35 37 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  38 +import org.springframework.scheduling.annotation.Async;
  39 +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
36 40 import org.springframework.stereotype.Service;
37 41 import org.springframework.transaction.TransactionDefinition;
38 42 import org.springframework.transaction.TransactionStatus;
  43 +import org.springframework.util.Assert;
39 44 import org.springframework.util.ObjectUtils;
40 45  
41 46 import java.io.File;
42 47 import java.time.LocalDateTime;
43 48 import java.util.*;
  49 +import java.util.concurrent.CompletableFuture;
  50 +import java.util.concurrent.ExecutionException;
44 51  
45 52 /**
46 53 * 媒体服务器节点管理
... ... @@ -104,6 +111,11 @@ public class MediaServerServiceImpl implements IMediaServerService {
104 111 @Autowired
105 112 private RedisTemplate<Object, Object> redisTemplate;
106 113  
  114 + @Qualifier("taskExecutor")
  115 + @Autowired
  116 + private ThreadPoolTaskExecutor taskExecutor;
  117 +
  118 +
107 119  
108 120  
109 121  
... ... @@ -118,7 +130,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
118 130 continue;
119 131 }
120 132 // 更新
121   - if (ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
  133 + if (!ssrcFactory.hasMediaServerSSRC(mediaServerItem.getId())) {
122 134 ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null);
123 135 }
124 136 // 查询redis是否存在此mediaServer
... ... @@ -151,7 +163,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
151 163 }
152 164  
153 165 if (streamId == null) {
154   - streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  166 + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
155 167 }
156 168 int ssrcCheckParam = 0;
157 169 if (ssrcCheck && tcpMode > 1) {
... ... @@ -160,7 +172,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
160 172 }
161 173 int rtpServerPort;
162 174 if (mediaServerItem.isRtpEnable()) {
163   - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, onlyAuto, reUsePort, tcpMode);
  175 + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode);
164 176 } else {
165 177 rtpServerPort = mediaServerItem.getRtpProxyPort();
166 178 }
... ... @@ -225,7 +237,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
225 237 mediaServerMapper.update(mediaSerItem);
226 238 MediaServerItem mediaServerItemInRedis = getOne(mediaSerItem.getId());
227 239 MediaServerItem mediaServerItemInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId());
228   - if (mediaServerItemInRedis == null || ssrcFactory.hasMediaServerSSRC(mediaSerItem.getId())) {
  240 + if (mediaServerItemInRedis == null || !ssrcFactory.hasMediaServerSSRC(mediaSerItem.getId())) {
229 241 ssrcFactory.initMediaServerSSRC(mediaServerItemInDataBase.getId(),null);
230 242 }
231 243 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItemInDataBase.getId();
... ... @@ -408,7 +420,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
408 420 }
409 421 mediaServerMapper.update(serverItem);
410 422 String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + zlmServerConfig.getGeneralMediaServerId();
411   - if (ssrcFactory.hasMediaServerSSRC(serverItem.getId())) {
  423 + if (!ssrcFactory.hasMediaServerSSRC(serverItem.getId())) {
412 424 ssrcFactory.initMediaServerSSRC(zlmServerConfig.getGeneralMediaServerId(), null);
413 425 }
414 426 redisTemplate.opsForValue().set(key, serverItem);
... ... @@ -758,4 +770,89 @@ public class MediaServerServiceImpl implements IMediaServerService {
758 770 return result;
759 771 }
760 772  
  773 + @Override
  774 + public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
  775 + Assert.notNull(app, "app不存在");
  776 + Assert.notNull(stream, "stream不存在");
  777 + Assert.notNull(startTime, "startTime不存在");
  778 + Assert.notNull(endTime, "endTime不存在");
  779 + Assert.notEmpty(mediaServerItems, "流媒体列表为空");
  780 +
  781 + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
  782 + for (int i = 0; i < mediaServerItems.size(); i++) {
  783 + completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i));
  784 + }
  785 + List<RecordFile> result = new ArrayList<>();
  786 + for (int i = 0; i < completableFutures.length; i++) {
  787 + try {
  788 + List<RecordFile> list = (List<RecordFile>) completableFutures[i].get();
  789 + if (!list.isEmpty()) {
  790 + for (int g = 0; g < list.size(); g++) {
  791 + list.get(g).setMediaServerId(mediaServerItems.get(i).getId());
  792 + }
  793 + result.addAll(list);
  794 + }
  795 + } catch (InterruptedException e) {
  796 + throw new RuntimeException(e);
  797 + } catch (ExecutionException e) {
  798 + throw new RuntimeException(e);
  799 + }
  800 + }
  801 + Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName);
  802 + result.sort(comparator);
  803 + return result;
  804 + }
  805 +
  806 + @Override
  807 + public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
  808 + Assert.notNull(app, "app不存在");
  809 + Assert.notNull(stream, "stream不存在");
  810 + Assert.notEmpty(mediaServerItems, "流媒体列表为空");
  811 + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
  812 +
  813 + for (int i = 0; i < mediaServerItems.size(); i++) {
  814 + completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i));
  815 + }
  816 + List<String> result = new ArrayList<>();
  817 + CompletableFuture.allOf(completableFutures).join();
  818 + for (CompletableFuture completableFuture : completableFutures) {
  819 + try {
  820 + List<String> list = (List<String>) completableFuture.get();
  821 + result.addAll(list);
  822 + } catch (InterruptedException e) {
  823 + throw new RuntimeException(e);
  824 + } catch (ExecutionException e) {
  825 + throw new RuntimeException(e);
  826 + }
  827 + }
  828 + Collections.sort(result);
  829 + return result;
  830 + }
  831 +
  832 + @Async
  833 + public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) {
  834 + JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month);
  835 + if (fileListJson != null && !fileListJson.isEmpty()) {
  836 + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
  837 + JSONArray data = fileListJson.getJSONArray("data");
  838 + return CompletableFuture.completedFuture(data.toJavaList(String.class));
  839 + }
  840 + }
  841 + return CompletableFuture.completedFuture(new ArrayList<>());
  842 + }
  843 +
  844 + @Async
  845 + public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) {
  846 + JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime);
  847 + if (fileListJson != null && !fileListJson.isEmpty()) {
  848 + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
  849 + JSONObject data = fileListJson.getJSONObject("data");
  850 + JSONArray list = data.getJSONArray("list");
  851 + if (list != null) {
  852 + return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class));
  853 + }
  854 + }
  855 + }
  856 + return CompletableFuture.completedFuture(new ArrayList<>());
  857 + }
761 858 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformChannelServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java 100644 → 100755
... ... @@ -251,7 +251,6 @@ public class PlatformServiceImpl implements IPlatformService {
251 251 // 设置平台离线,并重新注册
252 252 logger.info("[国标级联] 三次心跳超时, 平台{}({})离线", parentPlatform.getName(), parentPlatform.getServerGBId());
253 253 offline(parentPlatform, false);
254   -
255 254 }
256 255  
257 256 }else {
... ... @@ -266,6 +265,7 @@ public class PlatformServiceImpl implements IPlatformService {
266 265 platformCatch.setKeepAliveReply(0);
267 266 redisCatchStorage.updatePlatformCatchInfo(platformCatch);
268 267 }
  268 + logger.info("[发送心跳] 国标级联 发送心跳, code: {}, msg: {}", eventResult.statusCode, eventResult.msg);
269 269 });
270 270 } catch (SipException | InvalidArgumentException | ParseException e) {
271 271 logger.error("[命令发送失败] 国标级联 发送心跳: {}", e.getMessage());
... ... @@ -293,7 +293,7 @@ public class PlatformServiceImpl implements IPlatformService {
293 293 eventResult.statusCode, eventResult.msg);
294 294 offline(parentPlatform, false);
295 295 }, null);
296   - } catch (InvalidArgumentException | ParseException | SipException e) {
  296 + } catch (Exception e) {
297 297 logger.error("[命令发送失败] 国标级联定时注册: {}", e.getMessage());
298 298 }
299 299 }
... ...
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushUploadFileHandler.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisCloseStreamMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamCloseResponseListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamResponseListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusListMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisPushStreamStatusMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisStreamMsgListener.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorage.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceAlarmMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java 100644 → 100755
... ... @@ -193,7 +193,7 @@ public interface DeviceChannelMapper {
193 193 @Update(value = {"UPDATE wvp_device_channel SET status=false WHERE device_id=#{deviceId} AND channel_id=#{channelId}"})
194 194 void offline(String deviceId, String channelId);
195 195  
196   - @Update(value = {"UPDATE wvp_device_channel SET status=fasle WHERE device_id=#{deviceId}"})
  196 + @Update(value = {"UPDATE wvp_device_channel SET status=false WHERE device_id=#{deviceId}"})
197 197 void offlineByDeviceId(String deviceId);
198 198  
199 199 @Insert("<script> " +
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMobilePositionMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/LogMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/ParentPlatformMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformCatalogMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/RoleMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamProxyMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/ChannelSourceInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/LogDto.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/PlatformRegisterInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/RecordInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/Role.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/dao/dto/User.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 100644 → 100755
... ... @@ -16,6 +16,7 @@ import com.genersoft.iot.vmp.service.bean.GPSMsgInfo;
16 16 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
17 17 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
18 18 import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
  19 +import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
19 20 import com.genersoft.iot.vmp.storager.dao.dto.PlatformRegisterInfo;
20 21 import com.genersoft.iot.vmp.utils.DateUtil;
21 22 import com.genersoft.iot.vmp.utils.JsonUtil;
... ... @@ -41,6 +42,9 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
41 42 private DeviceChannelMapper deviceChannelMapper;
42 43  
43 44 @Autowired
  45 + private DeviceMapper deviceMapper;
  46 +
  47 + @Autowired
44 48 private UserSetting userSetting;
45 49  
46 50 @Autowired
... ... @@ -375,7 +379,8 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
375 379 for (Object o : keys) {
376 380 String key = (String) o;
377 381 Device device = JsonUtil.redisJsonToObject(redisTemplate, key, Device.class);
378   - if (Objects.nonNull(device)) { // 只取没有存过得
  382 + if (Objects.nonNull(device)) {
  383 + // 只取没有存过得
379 384 result.add(JsonUtil.redisJsonToObject(redisTemplate, key, Device.class));
380 385 }
381 386 }
... ... @@ -386,14 +391,22 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage {
386 391 @Override
387 392 public Device getDevice(String deviceId) {
388 393 String key = VideoManagerConstants.DEVICE_PREFIX + userSetting.getServerId() + "_" + deviceId;
389   - return JsonUtil.redisJsonToObject(redisTemplate, key, Device.class);
  394 + Device device = JsonUtil.redisJsonToObject(redisTemplate, key, Device.class);
  395 + if (device == null){
  396 + device = deviceMapper.getDeviceByDeviceId(deviceId);
  397 + if (device != null) {
  398 + updateDevice(device);
  399 + }
  400 + }
  401 + return device;
390 402 }
391 403  
392 404 @Override
393 405 public void updateGpsMsgInfo(GPSMsgInfo gpsMsgInfo) {
394 406 String key = VideoManagerConstants.WVP_STREAM_GPS_MSG_PREFIX + userSetting.getServerId() + "_" + gpsMsgInfo.getId();
395 407 Duration duration = Duration.ofSeconds(60L);
396   - redisTemplate.opsForValue().set(key, gpsMsgInfo, duration); // 默认GPS消息保存1分钟
  408 + redisTemplate.opsForValue().set(key, gpsMsgInfo, duration);
  409 + // 默认GPS消息保存1分钟
397 410 }
398 411  
399 412 @Override
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStorageImpl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/Coordtransform.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java 100644 → 100755
1 1 package com.genersoft.iot.vmp.utils;
2 2  
3 3  
  4 +import org.apache.commons.lang3.ObjectUtils;
  5 +
4 6 import java.time.Instant;
5 7 import java.time.LocalDate;
6 8 import java.time.LocalDateTime;
... ... @@ -109,6 +111,9 @@ public class DateUtil {
109 111 }
110 112  
111 113 public static long getDifferenceForNow(String keepaliveTime) {
  114 + if (ObjectUtils.isEmpty(keepaliveTime)) {
  115 + return 0;
  116 + }
112 117 Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime));
113 118 return ChronoUnit.MILLIS.between(beforeInstant, Instant.now());
114 119 }
... ...
src/main/java/com/genersoft/iot/vmp/utils/GitUtil.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/GpsUtil.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/JsonUtil.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java 100644 → 100755
1   -package com.genersoft.iot.vmp.utils;
2   -
3   -import org.springframework.beans.BeansException;
4   -import org.springframework.context.ApplicationContext;
5   -import org.springframework.context.ApplicationContextAware;
6   -import org.springframework.stereotype.Component;
7   -
8   -/**
9   - * @description:spring bean获取工厂,获取spring中的已初始化的bean
10   - * @author: swwheihei
11   - * @date: 2019年6月25日 下午4:51:52
12   - *
13   - */
14   -@Component
15   -public class SpringBeanFactory implements ApplicationContextAware {
16   -
17   - // Spring应用上下文环境
18   - private static ApplicationContext applicationContext;
19   -
20   - /**
21   - * 实现ApplicationContextAware接口的回调方法,设置上下文环境
22   - */
23   - @Override
24   - public void setApplicationContext(ApplicationContext applicationContext)
25   - throws BeansException {
26   - SpringBeanFactory.applicationContext = applicationContext;
27   - }
28   -
29   - public static ApplicationContext getApplicationContext() {
30   - return applicationContext;
31   - }
32   -
33   - /**
34   - * 获取对象 这里重写了bean方法,起主要作用
35   - */
36   - public static <T> T getBean(String beanId) throws BeansException {
37   - if (applicationContext == null) {
38   - return null;
39   - }
40   - return (T) applicationContext.getBean(beanId);
41   - }
42   -
43   - /**
44   - * 获取当前环境
45   - */
46   - public static String getActiveProfile() {
47   - return applicationContext.getEnvironment().getActiveProfiles()[0];
48   - }
49   -
50   -}
  1 +package com.genersoft.iot.vmp.utils;
  2 +
  3 +import org.springframework.beans.BeansException;
  4 +import org.springframework.context.ApplicationContext;
  5 +import org.springframework.context.ApplicationContextAware;
  6 +import org.springframework.stereotype.Component;
  7 +
  8 +/**
  9 + * @description:spring bean获取工厂,获取spring中的已初始化的bean
  10 + * @author: swwheihei
  11 + * @date: 2019年6月25日 下午4:51:52
  12 + *
  13 + */
  14 +@Component
  15 +public class SpringBeanFactory implements ApplicationContextAware {
  16 +
  17 + // Spring应用上下文环境
  18 + private static ApplicationContext applicationContext;
  19 +
  20 + /**
  21 + * 实现ApplicationContextAware接口的回调方法,设置上下文环境
  22 + */
  23 + @Override
  24 + public void setApplicationContext(ApplicationContext applicationContext)
  25 + throws BeansException {
  26 + SpringBeanFactory.applicationContext = applicationContext;
  27 + }
  28 +
  29 + public static ApplicationContext getApplicationContext() {
  30 + return applicationContext;
  31 + }
  32 +
  33 + /**
  34 + * 获取对象 这里重写了bean方法,起主要作用
  35 + */
  36 + public static <T> T getBean(String beanId) throws BeansException {
  37 + if (applicationContext == null) {
  38 + return null;
  39 + }
  40 + return (T) applicationContext.getBean(beanId);
  41 + }
  42 +
  43 + /**
  44 + * 获取当前环境
  45 + */
  46 + public static String getActiveProfile() {
  47 + return applicationContext.getEnvironment().getActiveProfiles()[0];
  48 + }
  49 +
  50 +}
... ...
src/main/java/com/genersoft/iot/vmp/utils/SystemInfoUtils.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/UJson.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/utils/redis/FastJsonRedisSerializer.java 100644 → 100755
1   -package com.genersoft.iot.vmp.utils.redis;
2   -
3   -import com.alibaba.fastjson2.JSON;
4   -import com.alibaba.fastjson2.JSONReader;
5   -import com.alibaba.fastjson2.JSONWriter;
6   -import org.springframework.data.redis.serializer.RedisSerializer;
7   -import org.springframework.data.redis.serializer.SerializationException;
8   -
9   -import java.nio.charset.Charset;
10   -
11   -/**
12   - * @description:使用fastjson实现redis的序列化
13   - * @author: swwheihei
14   - * @date: 2020年5月6日 下午8:40:11
15   - */
16   -public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
17   -
18   - public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
19   -
20   - private Class<T> clazz;
21   -
22   - public FastJsonRedisSerializer(Class<T> clazz) {
23   - super();
24   - this.clazz = clazz;
25   - }
26   -
27   - @Override
28   - public byte[] serialize(T t) throws SerializationException {
29   - if (t == null) {
30   - return new byte[0];
31   - }
32   - return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET);
33   - }
34   -
35   - @Override
36   - public T deserialize(byte[] bytes) throws SerializationException {
37   - if (bytes == null || bytes.length <= 0) {
38   - return null;
39   - }
40   - String str = new String(bytes, DEFAULT_CHARSET);
41   - return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
42   - }
43   -
44   -
45   -}
  1 +package com.genersoft.iot.vmp.utils.redis;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.alibaba.fastjson2.JSONReader;
  5 +import com.alibaba.fastjson2.JSONWriter;
  6 +import org.springframework.data.redis.serializer.RedisSerializer;
  7 +import org.springframework.data.redis.serializer.SerializationException;
  8 +
  9 +import java.nio.charset.Charset;
  10 +
  11 +/**
  12 + * @description:使用fastjson实现redis的序列化
  13 + * @author: swwheihei
  14 + * @date: 2020年5月6日 下午8:40:11
  15 + */
  16 +public class FastJsonRedisSerializer<T> implements RedisSerializer<T> {
  17 +
  18 + public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
  19 +
  20 + private Class<T> clazz;
  21 +
  22 + public FastJsonRedisSerializer(Class<T> clazz) {
  23 + super();
  24 + this.clazz = clazz;
  25 + }
  26 +
  27 + @Override
  28 + public byte[] serialize(T t) throws SerializationException {
  29 + if (t == null) {
  30 + return new byte[0];
  31 + }
  32 + return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName, JSONWriter.Feature.WritePairAsJavaBean).getBytes(DEFAULT_CHARSET);
  33 + }
  34 +
  35 + @Override
  36 + public T deserialize(byte[] bytes) throws SerializationException {
  37 + if (bytes == null || bytes.length <= 0) {
  38 + return null;
  39 + }
  40 + String str = new String(bytes, DEFAULT_CHARSET);
  41 + return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
  42 + }
  43 +
  44 +
  45 +}
... ...
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil.java 100644 → 100755
1   -package com.genersoft.iot.vmp.utils.redis;
2   -
3   -import org.springframework.data.redis.core.Cursor;
4   -import org.springframework.data.redis.core.RedisCallback;
5   -import org.springframework.data.redis.core.RedisTemplate;
6   -import org.springframework.data.redis.core.ScanOptions;
7   -
8   -import java.util.ArrayList;
9   -import java.util.HashSet;
10   -import java.util.List;
11   -import java.util.Set;
12   -
13   -/**
14   - * Redis工具类
15   - *
16   - * @author swwheihei
17   - * @date 2020年5月6日 下午8:27:29
18   - */
19   -@SuppressWarnings(value = {"rawtypes", "unchecked"})
20   -public class RedisUtil {
21   -
22   - /**
23   - * 模糊查询
24   - *
25   - * @param query 查询参数
26   - * @return
27   - */
28   - public static List<Object> scan(RedisTemplate redisTemplate, String query) {
29   -
30   - Set<String> resultKeys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
31   - ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();
32   - Cursor<byte[]> scan = connection.scan(scanOptions);
33   - Set<String> keys = new HashSet<>();
34   - while (scan.hasNext()) {
35   - byte[] next = scan.next();
36   - keys.add(new String(next));
37   - }
38   - return keys;
39   - });
40   -
41   - return new ArrayList<>(resultKeys);
42   - }
43   -}
44   -
45   -
46   -
  1 +package com.genersoft.iot.vmp.utils.redis;
  2 +
  3 +import com.google.common.collect.Lists;
  4 +import org.springframework.data.redis.core.Cursor;
  5 +import org.springframework.data.redis.core.RedisCallback;
  6 +import org.springframework.data.redis.core.RedisTemplate;
  7 +import org.springframework.data.redis.core.ScanOptions;
  8 +
  9 +import java.util.ArrayList;
  10 +import java.util.HashSet;
  11 +import java.util.List;
  12 +import java.util.Set;
  13 +
  14 +/**
  15 + * Redis工具类
  16 + *
  17 + * @author swwheihei
  18 + * @date 2020年5月6日 下午8:27:29
  19 + */
  20 +@SuppressWarnings(value = {"rawtypes", "unchecked"})
  21 +public class RedisUtil {
  22 +
  23 + /**
  24 + * 模糊查询
  25 + *
  26 + * @param query 查询参数
  27 + * @return
  28 + */
  29 + public static List<Object> scan(RedisTemplate redisTemplate, String query) {
  30 +
  31 + Set<String> resultKeys = (Set<String>) redisTemplate.execute((RedisCallback<Set<String>>) connection -> {
  32 + ScanOptions scanOptions = ScanOptions.scanOptions().match("*" + query + "*").count(1000).build();
  33 + Cursor<byte[]> scan = connection.scan(scanOptions);
  34 + Set<String> keys = new HashSet<>();
  35 + while (scan.hasNext()) {
  36 + byte[] next = scan.next();
  37 + keys.add(new String(next));
  38 + }
  39 + return keys;
  40 + });
  41 +
  42 + return Lists.newArrayList(resultKeys);
  43 + }
  44 +}
  45 +
  46 +
  47 +
... ...
src/main/java/com/genersoft/iot/vmp/utils/redis/RedisUtil2.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/BaseTree.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/BatchGBStreamParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultEx.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/DeferredResultFilter.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ErrorCode.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherPsSendInfo.java 0 → 100755
  1 +package com.genersoft.iot.vmp.vmanager.bean;
  2 +
  3 +public class OtherPsSendInfo {
  4 +
  5 + /**
  6 + * 发流IP
  7 + */
  8 + private String sendLocalIp;
  9 +
  10 + /**
  11 + * 发流端口
  12 + */
  13 + private int sendLocalPort;
  14 +
  15 + /**
  16 + * 收流IP
  17 + */
  18 + private String receiveIp;
  19 +
  20 + /**
  21 + * 收流端口
  22 + */
  23 + private int receivePort;
  24 +
  25 +
  26 + /**
  27 + * 会话ID
  28 + */
  29 + private String callId;
  30 +
  31 + /**
  32 + * 流ID
  33 + */
  34 + private String stream;
  35 +
  36 + /**
  37 + * 推流应用名
  38 + */
  39 + private String pushApp;
  40 +
  41 + /**
  42 + * 推流流ID
  43 + */
  44 + private String pushStream;
  45 +
  46 + /**
  47 + * 推流SSRC
  48 + */
  49 + private String pushSSRC;
  50 +
  51 + public String getSendLocalIp() {
  52 + return sendLocalIp;
  53 + }
  54 +
  55 + public void setSendLocalIp(String sendLocalIp) {
  56 + this.sendLocalIp = sendLocalIp;
  57 + }
  58 +
  59 + public int getSendLocalPort() {
  60 + return sendLocalPort;
  61 + }
  62 +
  63 + public void setSendLocalPort(int sendLocalPort) {
  64 + this.sendLocalPort = sendLocalPort;
  65 + }
  66 +
  67 + public String getReceiveIp() {
  68 + return receiveIp;
  69 + }
  70 +
  71 + public void setReceiveIp(String receiveIp) {
  72 + this.receiveIp = receiveIp;
  73 + }
  74 +
  75 + public int getReceivePort() {
  76 + return receivePort;
  77 + }
  78 +
  79 + public void setReceivePort(int receivePort) {
  80 + this.receivePort = receivePort;
  81 + }
  82 +
  83 + public String getCallId() {
  84 + return callId;
  85 + }
  86 +
  87 + public void setCallId(String callId) {
  88 + this.callId = callId;
  89 + }
  90 +
  91 + public String getStream() {
  92 + return stream;
  93 + }
  94 +
  95 + public void setStream(String stream) {
  96 + this.stream = stream;
  97 + }
  98 +
  99 + public String getPushApp() {
  100 + return pushApp;
  101 + }
  102 +
  103 + public void setPushApp(String pushApp) {
  104 + this.pushApp = pushApp;
  105 + }
  106 +
  107 + public String getPushStream() {
  108 + return pushStream;
  109 + }
  110 +
  111 + public void setPushStream(String pushStream) {
  112 + this.pushStream = pushStream;
  113 + }
  114 +
  115 + public String getPushSSRC() {
  116 + return pushSSRC;
  117 + }
  118 +
  119 + public void setPushSSRC(String pushSSRC) {
  120 + this.pushSSRC = pushSSRC;
  121 + }
  122 +
  123 + @Override
  124 + public String toString() {
  125 + return "OtherPsSendInfo{" +
  126 + "sendLocalIp='" + sendLocalIp + '\'' +
  127 + ", sendLocalPort=" + sendLocalPort +
  128 + ", receiveIp='" + receiveIp + '\'' +
  129 + ", receivePort=" + receivePort +
  130 + ", callId='" + callId + '\'' +
  131 + ", stream='" + stream + '\'' +
  132 + ", pushApp='" + pushApp + '\'' +
  133 + ", pushStream='" + pushStream + '\'' +
  134 + ", pushSSRC='" + pushSSRC + '\'' +
  135 + '}';
  136 + }
  137 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/OtherRtpSendInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PageInfo.java 0 → 100755
  1 +package com.genersoft.iot.vmp.vmanager.bean;
  2 +
  3 +import java.util.ArrayList;
  4 +import java.util.List;
  5 +
  6 +public class PageInfo<T> {
  7 + //当前页
  8 + private int pageNum;
  9 + //每页的数量
  10 + private int pageSize;
  11 + //当前页的数量
  12 + private int size;
  13 + //总页数
  14 + private int pages;
  15 + //总数
  16 + private int total;
  17 +
  18 + private List<T> resultData;
  19 +
  20 + private List<T> list;
  21 +
  22 + public PageInfo(List<T> resultData) {
  23 + this.resultData = resultData;
  24 + }
  25 +
  26 + public PageInfo() {
  27 + }
  28 +
  29 + public void startPage(int page, int count) {
  30 + if (count <= 0) count = 10;
  31 + if (page <= 0) page = 1;
  32 + this.pageNum = page;
  33 + this.pageSize = count;
  34 + this.total = resultData.size();
  35 +
  36 + this.pages = total % count == 0 ? total / count : total / count + 1;
  37 + int fromIndx = (page - 1) * count;
  38 + if (fromIndx > this.total - 1) {
  39 + this.list = new ArrayList<>();
  40 + this.size = 0;
  41 + return;
  42 + }
  43 +
  44 + int toIndx = page * count;
  45 + if (toIndx > this.total) {
  46 + toIndx = this.total;
  47 + }
  48 + this.list = this.resultData.subList(fromIndx, toIndx);
  49 + this.size = this.list.size();
  50 + }
  51 +
  52 + public int getPageNum() {
  53 + return pageNum;
  54 + }
  55 +
  56 + public void setPageNum(int pageNum) {
  57 + this.pageNum = pageNum;
  58 + }
  59 +
  60 + public int getPageSize() {
  61 + return pageSize;
  62 + }
  63 +
  64 + public void setPageSize(int pageSize) {
  65 + this.pageSize = pageSize;
  66 + }
  67 +
  68 + public int getSize() {
  69 + return size;
  70 + }
  71 +
  72 + public void setSize(int size) {
  73 + this.size = size;
  74 + }
  75 +
  76 + public int getPages() {
  77 + return pages;
  78 + }
  79 +
  80 + public void setPages(int pages) {
  81 + this.pages = pages;
  82 + }
  83 +
  84 + public int getTotal() {
  85 + return total;
  86 + }
  87 +
  88 + public void setTotal(int total) {
  89 + this.total = total;
  90 + }
  91 +
  92 + public List<T> getList() {
  93 + return list;
  94 + }
  95 +
  96 + public void setList(List<T> list) {
  97 + this.list = list;
  98 + }
  99 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/PlayTypeEnum.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/RecordFile.java 0 → 100755
  1 +package com.genersoft.iot.vmp.vmanager.bean;
  2 +
  3 +public class RecordFile {
  4 + private String app;
  5 + private String stream;
  6 +
  7 + private String fileName;
  8 +
  9 + private String mediaServerId;
  10 +
  11 + private String date;
  12 +
  13 +
  14 + public String getApp() {
  15 + return app;
  16 + }
  17 +
  18 + public void setApp(String app) {
  19 + this.app = app;
  20 + }
  21 +
  22 + public String getStream() {
  23 + return stream;
  24 + }
  25 +
  26 + public void setStream(String stream) {
  27 + this.stream = stream;
  28 + }
  29 +
  30 + public String getFileName() {
  31 + return fileName;
  32 + }
  33 +
  34 + public void setFileName(String fileName) {
  35 + this.fileName = fileName;
  36 + }
  37 +
  38 + public String getMediaServerId() {
  39 + return mediaServerId;
  40 + }
  41 +
  42 + public void setMediaServerId(String mediaServerId) {
  43 + this.mediaServerId = mediaServerId;
  44 + }
  45 +
  46 + public String getDate() {
  47 + return date;
  48 + }
  49 +
  50 + public void setDate(String date) {
  51 + this.date = date;
  52 + }
  53 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceBaseInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/ResourceInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SnapPath.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamPushExcelDto.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/SystemConfigInfo.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java 0 → 100755
  1 +package com.genersoft.iot.vmp.vmanager.cloudRecord;
  2 +
  3 +import com.genersoft.iot.vmp.conf.DynamicTask;
  4 +import com.genersoft.iot.vmp.conf.UserSetting;
  5 +import com.genersoft.iot.vmp.conf.exception.ControllerException;
  6 +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
  7 +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
  8 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  9 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  10 +import com.genersoft.iot.vmp.service.IMediaServerService;
  11 +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  12 +import com.genersoft.iot.vmp.vmanager.bean.PageInfo;
  13 +import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
  14 +import io.swagger.v3.oas.annotations.Operation;
  15 +import io.swagger.v3.oas.annotations.Parameter;
  16 +import io.swagger.v3.oas.annotations.tags.Tag;
  17 +import org.apache.commons.lang3.ObjectUtils;
  18 +import org.slf4j.Logger;
  19 +import org.slf4j.LoggerFactory;
  20 +import org.springframework.beans.factory.annotation.Autowired;
  21 +import org.springframework.data.redis.core.RedisTemplate;
  22 +import org.springframework.web.bind.annotation.*;
  23 +
  24 +import java.util.ArrayList;
  25 +import java.util.Calendar;
  26 +import java.util.List;
  27 +
  28 +@SuppressWarnings("rawtypes")
  29 +@Tag(name = "云端录像接口")
  30 +
  31 +@RestController
  32 +@RequestMapping("/api/cloud/record")
  33 +public class CloudRecordController {
  34 +
  35 + @Autowired
  36 + private ZLMServerFactory zlmServerFactory;
  37 +
  38 + @Autowired
  39 + private SendRtpPortManager sendRtpPortManager;
  40 +
  41 + private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class);
  42 +
  43 + @Autowired
  44 + private ZlmHttpHookSubscribe hookSubscribe;
  45 +
  46 + @Autowired
  47 + private IMediaServerService mediaServerService;
  48 +
  49 + @Autowired
  50 + private UserSetting userSetting;
  51 +
  52 + @Autowired
  53 + private DynamicTask dynamicTask;
  54 +
  55 + @Autowired
  56 + private RedisTemplate<Object, Object> redisTemplate;
  57 +
  58 + @ResponseBody
  59 + @GetMapping("/date/list")
  60 + @Operation(summary = "查询存在云端录像的日期")
  61 + @Parameter(name = "app", description = "应用名", required = true)
  62 + @Parameter(name = "stream", description = "流ID", required = true)
  63 + @Parameter(name = "year", description = "年,置空则查询当年", required = false)
  64 + @Parameter(name = "month", description = "月,置空则查询当月", required = false)
  65 + @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部", required = false)
  66 + public List<String> openRtpServer(
  67 + @RequestParam String app,
  68 + @RequestParam String stream,
  69 + @RequestParam(required = false) int year,
  70 + @RequestParam(required = false) int month,
  71 + @RequestParam(required = false) String mediaServerId
  72 +
  73 + ) {
  74 + logger.info("[云端录像] 查询存在云端录像的日期 app->{}, stream->{}, mediaServerId->{}, year->{}, month->{}",
  75 + app, stream, mediaServerId, year, month);
  76 + Calendar calendar = Calendar.getInstance();
  77 + if (ObjectUtils.isEmpty(year)) {
  78 + year = calendar.get(Calendar.YEAR);
  79 + }
  80 + if (ObjectUtils.isEmpty(month)) {
  81 + month = calendar.get(Calendar.MONTH) + 1;
  82 + }
  83 + List<MediaServerItem> mediaServerItems;
  84 + if (!ObjectUtils.isEmpty(mediaServerId)) {
  85 + mediaServerItems = new ArrayList<>();
  86 + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
  87 + if (mediaServerItem == null) {
  88 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
  89 + }
  90 + mediaServerItems.add(mediaServerItem);
  91 + } else {
  92 + mediaServerItems = mediaServerService.getAll();
  93 + }
  94 + if (mediaServerItems.isEmpty()) {
  95 + return new ArrayList<>();
  96 + }
  97 +
  98 + return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems);
  99 + }
  100 +
  101 + @ResponseBody
  102 + @GetMapping("/list")
  103 + @Operation(summary = "分页查询云端录像")
  104 + @Parameter(name = "app", description = "应用名", required = true)
  105 + @Parameter(name = "stream", description = "流ID", required = true)
  106 + @Parameter(name = "page", description = "当前页", required = false)
  107 + @Parameter(name = "count", description = "每页查询数量", required = false)
  108 + @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true)
  109 + @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true)
  110 + @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false)
  111 + public PageInfo<RecordFile> openRtpServer(
  112 + @RequestParam String app,
  113 + @RequestParam String stream,
  114 + @RequestParam int page,
  115 + @RequestParam int count,
  116 + @RequestParam String startTime,
  117 + @RequestParam String endTime,
  118 + @RequestParam(required = false) String mediaServerId
  119 +
  120 + ) {
  121 + logger.info("[云端录像] 查询 app->{}, stream->{}, mediaServerId->{}, page->{}, count->{}, startTime->{}, endTime->{}",
  122 + app, stream, mediaServerId, page, count, startTime, endTime);
  123 +
  124 + List<MediaServerItem> mediaServerItems;
  125 + if (!ObjectUtils.isEmpty(mediaServerId)) {
  126 + mediaServerItems = new ArrayList<>();
  127 + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId);
  128 + if (mediaServerItem == null) {
  129 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId);
  130 + }
  131 + mediaServerItems.add(mediaServerItem);
  132 + } else {
  133 + mediaServerItems = mediaServerService.getAll();
  134 + }
  135 + if (mediaServerItems.isEmpty()) {
  136 + return new PageInfo<>();
  137 + }
  138 + List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems);
  139 + PageInfo<RecordFile> pageInfo = new PageInfo<>(records);
  140 + pageInfo.startPage(page, count);
  141 + return pageInfo;
  142 + }
  143 +
  144 +
  145 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/bean/GbStreamParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/ChannelReduce.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/bean/UpdateChannelParam.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/bean/PlayResult.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java 100644 → 100755
... ... @@ -61,7 +61,7 @@ public class LogController {
61 61 query = null;
62 62 }
63 63  
64   - if (!userSetting.getLogInDatebase()) {
  64 + if (!userSetting.getLogInDatabase()) {
65 65 logger.warn("自动记录日志功能已关闭,查询结果可能不完整。");
66 66 }
67 67  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java 0 → 100755
  1 +package com.genersoft.iot.vmp.vmanager.ps;
  2 +
  3 +import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  5 +import com.genersoft.iot.vmp.conf.DynamicTask;
  6 +import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.ControllerException;
  8 +import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager;
  9 +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
  10 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  11 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  12 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForRtpServerTimeout;
  13 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  14 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  15 +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRtpServerTimeoutHookParam;
  16 +import com.genersoft.iot.vmp.service.IMediaServerService;
  17 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  18 +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  19 +import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
  20 +import io.swagger.v3.oas.annotations.Operation;
  21 +import io.swagger.v3.oas.annotations.Parameter;
  22 +import io.swagger.v3.oas.annotations.tags.Tag;
  23 +import okhttp3.OkHttpClient;
  24 +import okhttp3.Request;
  25 +import org.slf4j.Logger;
  26 +import org.slf4j.LoggerFactory;
  27 +import org.springframework.beans.factory.annotation.Autowired;
  28 +import org.springframework.data.redis.core.RedisTemplate;
  29 +import org.springframework.web.bind.annotation.*;
  30 +
  31 +import java.io.IOException;
  32 +import java.util.HashMap;
  33 +import java.util.List;
  34 +import java.util.Map;
  35 +import java.util.UUID;
  36 +import java.util.concurrent.TimeUnit;
  37 +
  38 +@SuppressWarnings("rawtypes")
  39 +@Tag(name = "第三方PS服务对接")
  40 +
  41 +@RestController
  42 +@RequestMapping("/api/ps")
  43 +public class PsController {
  44 +
  45 + private final static Logger logger = LoggerFactory.getLogger(PsController.class);
  46 +
  47 + @Autowired
  48 + private ZLMServerFactory zlmServerFactory;
  49 +
  50 + @Autowired
  51 + private ZlmHttpHookSubscribe hookSubscribe;
  52 +
  53 + @Autowired
  54 + private IMediaServerService mediaServerService;
  55 +
  56 + @Autowired
  57 + private SendRtpPortManager sendRtpPortManager;
  58 +
  59 + @Autowired
  60 + private UserSetting userSetting;
  61 +
  62 + @Autowired
  63 + private DynamicTask dynamicTask;
  64 +
  65 +
  66 + @Autowired
  67 + private RedisTemplate<Object, Object> redisTemplate;
  68 +
  69 +
  70 + @GetMapping(value = "/receive/open")
  71 + @ResponseBody
  72 + @Operation(summary = "开启收流和获取发流信息")
  73 + @Parameter(name = "isSend", description = "是否发送,false时只开启收流, true同时返回推流信息", required = true)
  74 + @Parameter(name = "callId", description = "整个过程的唯一标识,为了与后续接口关联", required = true)
  75 + @Parameter(name = "ssrc", description = "来源流的SSRC,不传则不校验来源ssrc", required = false)
  76 + @Parameter(name = "stream", description = "形成的流的ID", required = true)
  77 + @Parameter(name = "tcpMode", description = "收流模式, 0为UDP, 1为TCP被动", required = true)
  78 + @Parameter(name = "callBack", description = "回调地址,如果收流超时会通道回调通知,回调为get请求,参数为callId", required = true)
  79 + public OtherPsSendInfo openRtpServer(Boolean isSend, @RequestParam(required = false)String ssrc, String callId, String stream, Integer tcpMode, String callBack) {
  80 +
  81 + logger.info("[第三方PS服务对接->开启收流和获取发流信息] isSend->{}, ssrc->{}, callId->{}, stream->{}, tcpMode->{}, callBack->{}",
  82 + isSend, ssrc, callId, stream, tcpMode==0?"UDP":"TCP被动", callBack);
  83 +
  84 + MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
  85 + if (mediaServerItem == null) {
  86 + throw new ControllerException(ErrorCode.ERROR100.getCode(),"没有可用的MediaServer");
  87 + }
  88 + if (stream == null) {
  89 + throw new ControllerException(ErrorCode.ERROR100.getCode(),"stream参数不可为空");
  90 + }
  91 + if (isSend != null && isSend && callId == null) {
  92 + throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空");
  93 + }
  94 + long ssrcInt = 0;
  95 + if (ssrc != null) {
  96 + try {
  97 + ssrcInt = Long.parseLong(ssrc);
  98 + }catch (NumberFormatException e) {
  99 + throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误");
  100 + }
  101 + }
  102 + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + callId + "_" + stream;
  103 + int localPort = zlmServerFactory.createRTPServer(mediaServerItem, stream, ssrcInt, null, false, tcpMode);
  104 + if (localPort == 0) {
  105 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取端口失败");
  106 + }
  107 + // 注册回调如果rtp收流超时则通过回调发送通知
  108 + if (callBack != null) {
  109 + HookSubscribeForRtpServerTimeout hookSubscribeForRtpServerTimeout = HookSubscribeFactory.on_rtp_server_timeout(stream, String.valueOf(ssrcInt), mediaServerItem.getId());
  110 + // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
  111 + hookSubscribe.addSubscribe(hookSubscribeForRtpServerTimeout,
  112 + (mediaServerItemInUse, hookParam)->{
  113 + OnRtpServerTimeoutHookParam serverTimeoutHookParam = (OnRtpServerTimeoutHookParam) hookParam;
  114 + if (stream.equals(serverTimeoutHookParam.getStream_id())) {
  115 + logger.info("[第三方PS服务对接->开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调", callId);
  116 + // 将信息写入redis中,以备后用
  117 + redisTemplate.delete(receiveKey);
  118 + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
  119 + OkHttpClient client = httpClientBuilder.build();
  120 + String url = callBack + "?callId=" + callId;
  121 + Request request = new Request.Builder().get().url(url).build();
  122 + try {
  123 + client.newCall(request).execute();
  124 + } catch (IOException e) {
  125 + logger.error("[第三方PS服务对接->开启收流和获取发流信息] 等待收流超时 callId->{}, 发送回调失败", callId, e);
  126 + }
  127 + hookSubscribe.removeSubscribe(hookSubscribeForRtpServerTimeout);
  128 + }
  129 + });
  130 + }
  131 + OtherPsSendInfo otherPsSendInfo = new OtherPsSendInfo();
  132 + otherPsSendInfo.setReceiveIp(mediaServerItem.getSdpIp());
  133 + otherPsSendInfo.setReceivePort(localPort);
  134 + otherPsSendInfo.setCallId(callId);
  135 + otherPsSendInfo.setStream(stream);
  136 +
  137 + // 将信息写入redis中,以备后用
  138 + redisTemplate.opsForValue().set(receiveKey, otherPsSendInfo);
  139 + if (isSend != null && isSend) {
  140 + String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_" + callId;
  141 + // 预创建发流信息
  142 + int port = sendRtpPortManager.getNextPort(mediaServerItem);
  143 +
  144 + otherPsSendInfo.setSendLocalIp(mediaServerItem.getSdpIp());
  145 + otherPsSendInfo.setSendLocalPort(port);
  146 + // 将信息写入redis中,以备后用
  147 + redisTemplate.opsForValue().set(key, otherPsSendInfo, 300, TimeUnit.SECONDS);
  148 + logger.info("[第三方PS服务对接->开启收流和获取发流信息] 结果,callId->{}, {}", callId, otherPsSendInfo);
  149 + }
  150 + return otherPsSendInfo;
  151 + }
  152 +
  153 + @GetMapping(value = "/receive/close")
  154 + @ResponseBody
  155 + @Operation(summary = "关闭收流")
  156 + @Parameter(name = "stream", description = "流的ID", required = true)
  157 + public void closeRtpServer(String stream) {
  158 + logger.info("[第三方PS服务对接->关闭收流] stream->{}", stream);
  159 + MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
  160 + zlmServerFactory.closeRtpServer(mediaServerItem,stream);
  161 + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_*_" + stream;
  162 + List<Object> scan = RedisUtil.scan(redisTemplate, receiveKey);
  163 + if (!scan.isEmpty()) {
  164 + for (Object key : scan) {
  165 + // 将信息写入redis中,以备后用
  166 + redisTemplate.delete(key);
  167 + }
  168 + }
  169 + }
  170 +
  171 + @GetMapping(value = "/send/start")
  172 + @ResponseBody
  173 + @Operation(summary = "发送流")
  174 + @Parameter(name = "ssrc", description = "发送流的SSRC", required = true)
  175 + @Parameter(name = "dstIp", description = "目标收流IP", required = true)
  176 + @Parameter(name = "dstPort", description = "目标收流端口", required = true)
  177 + @Parameter(name = "app", description = "待发送应用名", required = true)
  178 + @Parameter(name = "stream", description = "待发送流Id", required = true)
  179 + @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true)
  180 + @Parameter(name = "isUdp", description = "是否为UDP", required = true)
  181 + public void sendRTP(String ssrc,
  182 + String dstIp,
  183 + Integer dstPort,
  184 + String app,
  185 + String stream,
  186 + String callId,
  187 + Boolean isUdp
  188 + ) {
  189 + logger.info("[第三方PS服务对接->发送流] " +
  190 + "ssrc->{}, \r\n" +
  191 + "dstIp->{}, \n" +
  192 + "dstPort->{}, \n" +
  193 + "app->{}, \n" +
  194 + "stream->{}, \n" +
  195 + "callId->{} \n",
  196 + ssrc,
  197 + dstIp,
  198 + dstPort,
  199 + app,
  200 + stream,
  201 + callId);
  202 + MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
  203 + String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_" + callId;
  204 + OtherPsSendInfo sendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(key);
  205 + if (sendInfo == null) {
  206 + sendInfo = new OtherPsSendInfo();
  207 + }
  208 + sendInfo.setPushApp(app);
  209 + sendInfo.setPushStream(stream);
  210 + sendInfo.setPushSSRC(ssrc);
  211 +
  212 + Map<String, Object> param;
  213 +
  214 +
  215 + param = new HashMap<>();
  216 + param.put("vhost","__defaultVhost__");
  217 + param.put("app",app);
  218 + param.put("stream",stream);
  219 + param.put("ssrc", ssrc);
  220 +
  221 + param.put("dst_url", dstIp);
  222 + param.put("dst_port", dstPort);
  223 + String is_Udp = isUdp ? "1" : "0";
  224 + param.put("is_udp", is_Udp);
  225 + param.put("src_port", sendInfo.getSendLocalPort());
  226 +
  227 +
  228 + Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
  229 + if (streamReady) {
  230 + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param);
  231 + if (jsonObject.getInteger("code") == 0) {
  232 + logger.info("[第三方PS服务对接->发送流] 视频流发流成功,callId->{},param->{}", callId, param);
  233 + redisTemplate.opsForValue().set(key, sendInfo);
  234 + }else {
  235 + redisTemplate.delete(key);
  236 + logger.info("[第三方PS服务对接->发送流] 视频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg"));
  237 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[视频流发流失败] " + jsonObject.getString("msg"));
  238 + }
  239 + }else {
  240 + logger.info("[第三方PS服务对接->发送流] 流不存在,等待流上线,callId->{}", callId);
  241 + String uuid = UUID.randomUUID().toString();
  242 + HookSubscribeForStreamChange hookSubscribeForStreamChange = HookSubscribeFactory.on_stream_changed(app, stream, true, "rtsp", mediaServerItem.getId());
  243 + dynamicTask.startDelay(uuid, ()->{
  244 + logger.info("[第三方PS服务对接->发送流] 等待流上线超时 callId->{}", callId);
  245 + redisTemplate.delete(key);
  246 + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
  247 + }, 10000);
  248 +
  249 + // 订阅 zlm启动事件, 新的zlm也会从这里进入系统
  250 + OtherPsSendInfo finalSendInfo = sendInfo;
  251 + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
  252 + hookSubscribe.addSubscribe(hookSubscribeForStreamChange,
  253 + (mediaServerItemInUse, response)->{
  254 + dynamicTask.stop(uuid);
  255 + logger.info("[第三方PS服务对接->发送流] 流上线,开始发流 callId->{}", callId);
  256 + try {
  257 + Thread.sleep(400);
  258 + } catch (InterruptedException e) {
  259 + throw new RuntimeException(e);
  260 + }
  261 + JSONObject jsonObject = zlmServerFactory.startSendRtpStream(mediaServerItem, param);
  262 + if (jsonObject.getInteger("code") == 0) {
  263 + logger.info("[第三方PS服务对接->发送流] 视频流发流成功,callId->{},param->{}", callId, param);
  264 + redisTemplate.opsForValue().set(key, finalSendInfo);
  265 + }else {
  266 + redisTemplate.delete(key);
  267 + logger.info("[第三方PS服务对接->发送流] 视频流发流失败,callId->{}, {}", callId, jsonObject.getString("msg"));
  268 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "[视频流发流失败] " + jsonObject.getString("msg"));
  269 + }
  270 + hookSubscribe.removeSubscribe(hookSubscribeForStreamChange);
  271 + });
  272 + }
  273 + }
  274 +
  275 + @GetMapping(value = "/send/stop")
  276 + @ResponseBody
  277 + @Operation(summary = "关闭发送流")
  278 + @Parameter(name = "callId", description = "整个过程的唯一标识,不传则使用随机端口发流", required = true)
  279 + public void closeSendRTP(String callId) {
  280 + logger.info("[第三方PS服务对接->关闭发送流] callId->{}", callId);
  281 + String key = VideoManagerConstants.WVP_OTHER_SEND_PS_INFO + userSetting.getServerId() + "_" + callId;
  282 + OtherPsSendInfo sendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(key);
  283 + if (sendInfo == null){
  284 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未开启发流");
  285 + }
  286 + Map<String, Object> param = new HashMap<>();
  287 + param.put("vhost","__defaultVhost__");
  288 + param.put("app",sendInfo.getPushApp());
  289 + param.put("stream",sendInfo.getPushStream());
  290 + param.put("ssrc",sendInfo.getPushSSRC());
  291 + MediaServerItem mediaServerItem = mediaServerService.getDefaultMediaServer();
  292 + Boolean result = zlmServerFactory.stopSendRtpStream(mediaServerItem, param);
  293 + if (!result) {
  294 + logger.info("[第三方PS服务对接->关闭发送流] 失败 callId->{}", callId);
  295 + throw new ControllerException(ErrorCode.ERROR100.getCode(), "停止发流失败");
  296 + }else {
  297 + logger.info("[第三方PS服务对接->关闭发送流] 成功 callId->{}", callId);
  298 + }
  299 + redisTemplate.delete(key);
  300 + }
  301 +
  302 +
  303 + @GetMapping(value = "/getTestPort")
  304 + @ResponseBody
  305 + public int getTestPort() {
  306 + MediaServerItem defaultMediaServer = mediaServerService.getDefaultMediaServer();
  307 +
  308 +// for (int i = 0; i <300; i++) {
  309 +// new Thread(() -> {
  310 +// int nextPort = sendRtpPortManager.getNextPort(defaultMediaServer);
  311 +// try {
  312 +// Thread.sleep((int)Math.random()*10);
  313 +// } catch (InterruptedException e) {
  314 +// throw new RuntimeException(e);
  315 +// }
  316 +// System.out.println(nextPort);
  317 +// }).start();
  318 +// }
  319 +
  320 + return sendRtpPortManager.getNextPort(defaultMediaServer);
  321 + }
  322 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/rtp/RtpController.java 100644 → 100755
... ... @@ -91,10 +91,10 @@ public class RtpController {
91 91 if (isSend != null && isSend && callId == null) {
92 92 throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空");
93 93 }
94   - int ssrcInt = 0;
  94 + long ssrcInt = 0;
95 95 if (ssrc != null) {
96 96 try {
97   - ssrcInt = Integer.parseInt(ssrc);
  97 + ssrcInt = Long.parseLong(ssrc);
98 98 }catch (NumberFormatException e) {
99 99 throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误");
100 100 }
... ... @@ -247,7 +247,6 @@ public class RtpController {
247 247 String is_Udp = isUdp ? "1" : "0";
248 248 paramForAudio.put("is_udp", is_Udp);
249 249 paramForAudio.put("src_port", sendInfo.getSendLocalPortForAudio());
250   - paramForAudio.put("use_ps", "0");
251 250 paramForAudio.put("only_audio", "1");
252 251 if (ptForAudio != null) {
253 252 paramForAudio.put("pt", ptForAudio);
... ... @@ -268,7 +267,6 @@ public class RtpController {
268 267 String is_Udp = isUdp ? "1" : "0";
269 268 paramForVideo.put("is_udp", is_Udp);
270 269 paramForVideo.put("src_port", sendInfo.getSendLocalPortForVideo());
271   - paramForVideo.put("use_ps", "0");
272 270 paramForVideo.put("only_audio", "0");
273 271 if (ptForVideo != null) {
274 272 paramForVideo.put("pt", ptForVideo);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/streamProxy/StreamProxyController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/streamPush/StreamPushController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/user/RoleController.java 100644 → 100755
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java 100644 → 100755
... ... @@ -58,7 +58,7 @@ public class UserController {
58 58 if (user == null) {
59 59 throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
60 60 }else {
61   - String jwt = JwtUtils.createToken(username, password, user.getRole().getId());
  61 + String jwt = JwtUtils.createToken(username);
62 62 response.setHeader(JwtUtils.getHeader(), jwt);
63 63 user.setAccessToken(jwt);
64 64 }
... ...
src/main/resources/all-application.yml
... ... @@ -178,7 +178,7 @@ user-settings:
178 178 # 国标是否录制
179 179 record-sip: true
180 180 # 是否将日志存储进数据库
181   - logInDatebase: true
  181 + logInDatabase: true
182 182 # 使用推流状态作为推流通道状态
183 183 use-pushing-as-status: true
184 184 # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启
... ...
src/main/resources/application-dev.yml
... ... @@ -19,14 +19,14 @@ spring:
19 19 # [可选] 数据库 DB
20 20 database: 7
21 21 # [可选] 访问密码,若你的redis服务器没有设置密码,就不需要用密码去连接
22   - password:
  22 + password: luna
23 23 # [可选] 超时时间
24 24 timeout: 10000
25 25 # mysql数据源
26 26 datasource:
27 27 type: com.zaxxer.hikari.HikariDataSource
28 28 driver-class-name: com.mysql.cj.jdbc.Driver
29   - url: jdbc:mysql://127.0.0.1:3306/test_gb-89wulian?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
  29 + url: jdbc:mysql://127.0.0.1:3306/wvp?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true&serverTimezone=PRC&useSSL=false&allowMultiQueries=true
30 30 username: root
31 31 password: root
32 32 hikari:
... ... @@ -38,7 +38,7 @@ spring:
38 38 max-lifetime: 1200000 # 是池中连接关闭后的最长生命周期(以毫秒为单位)
39 39 #[可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口
40 40 server:
41   - port: 18978
  41 + port: 8080
42 42 # [可选] HTTPS配置, 默认不开启
43 43 ssl:
44 44 # [可选] 是否开启HTTPS访问
... ... @@ -56,7 +56,7 @@ sip:
56 56 # 如果要监听多张网卡,可以使用逗号分隔多个IP, 例如: 192.168.1.4,10.0.0.4
57 57 # 如果不明白,就使用0.0.0.0,大部分情况都是可以的
58 58 # 请不要使用127.0.0.1,任何包括localhost在内的域名都是不可以的。
59   - ip: 192.168.1.18
  59 + ip: 172.19.128.50
60 60 # [可选] 28181服务监听的端口
61 61 port: 8116
62 62 # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007)
... ... @@ -73,21 +73,21 @@ sip:
73 73  
74 74 #zlm 默认服务器配置
75 75 media:
76   - id: 89wulian-one
  76 + id: zlmediakit-local
77 77 # [必须修改] zlm服务器的内网IP
78   - ip: 192.168.1.18
  78 + ip: 172.19.128.50
79 79 # [必须修改] zlm服务器的http.port
80   - http-port: 80
  80 + http-port: 9092
81 81 # [可选] 返回流地址时的ip,置空使用 media.ip
82   - stream-ip: 192.168.1.18
  82 + stream-ip: 172.19.128.50
83 83 # [可选] wvp在国标信令中使用的ip,此ip为摄像机可以访问到的ip, 置空使用 media.ip
84   - sdp-ip: 192.168.1.18
  84 + sdp-ip: 172.19.128.50
85 85 # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip
86   - hook-ip: 192.168.1.18
  86 + hook-ip: 172.19.128.50
87 87 # [可选] zlm服务器的http.sslport, 置空使用zlm配置文件配置
88   - http-ssl-port: 443
  88 + http-ssl-port: 1443
89 89 # [可选] zlm服务器的hook.admin_params=secret
90   - secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc
  90 + secret: 10000
91 91 # 启用多端口模式, 多端口模式使用端口区分每路流,兼容性更好。 单端口使用流的ssrc区分, 点播超时建议使用多端口测试
92 92 rtp:
93 93 # [可选] 是否启用多端口模式, 开启后会在portRange范围内选择端口用于媒体流传输
... ...
src/main/resources/application.yml
... ... @@ -2,4 +2,4 @@ spring:
2 2 application:
3 3 name: wvp
4 4 profiles:
5   - active: local
6 5 \ No newline at end of file
  6 + active: dev
7 7 \ No newline at end of file
... ...
web_src/src/App.vue 100644 → 100755
web_src/src/assets/icons.png 100644 → 100755

11.3 KB | W: | H:

11.3 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/loading.png 100644 → 100755

2.7 KB | W: | H:

2.7 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/login-bg.jpg 100644 → 100755

3.97 KB | W: | H:

3.97 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/login-cloud.png 100644 → 100755

3.31 KB | W: | H:

3.31 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/logo.png 100644 → 100755

65.5 KB | W: | H:

65.5 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/play.png 100644 → 100755

546 Bytes | W: | H:

546 Bytes | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/assets/zlm-log.png 100644 → 100755

47.9 KB | W: | H:

47.9 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
web_src/src/components/CloudRecord.vue 100644 → 100755
... ... @@ -47,19 +47,17 @@
47 47 :total="total">
48 48 </el-pagination>
49 49 </div>
50   - <cloud-record-detail ref="cloudRecordDetail" v-if="recordDetail" :recordFile="chooseRecord" :mediaServerId="mediaServerId" :mediaServerPath="mediaServerPath" ></cloud-record-detail>
51 50  
52 51 </div>
53 52 </template>
54 53  
55 54 <script>
56 55 import uiHeader from '../layout/UiHeader.vue'
57   - import cloudRecordDetail from './CloudRecordDetail.vue'
58 56 import MediaServer from './service/MediaServer'
59 57 export default {
60 58 name: 'app',
61 59 components: {
62   - uiHeader, cloudRecordDetail
  60 + uiHeader
63 61 },
64 62 data() {
65 63 return {
... ... @@ -178,7 +176,7 @@
178 176 // }).catch(function (error) {
179 177 // console.log(error);
180 178 // });
181   -
  179 + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
182 180 },
183 181 deleteRecord(){
184 182 // TODO
... ...
web_src/src/components/CloudRecordDetail.vue 100644 → 100755
1 1 <template>
2   - <div id="recordDetail">
3   - <el-container>
  2 + <div id="recordDetail" style="width: 100%">
  3 + <div class="page-header" style="margin-bottom: 0">
  4 + <div class="page-title">
  5 + <el-page-header @back="backToList" content="云端录像"></el-page-header>
  6 + </div>
  7 +
  8 + <div class="page-header-btn" v-if="!this.$route.params.mediaServerId" style="padding-right: 1rem">
  9 + <!-- 节点选择:-->
  10 + <!-- <el-select size="mini" @change="chooseMediaChange" style="width: 16rem; margin-right: 1rem;" v-model="mediaServerId" placeholder="请选择" >-->
  11 + <!-- <el-option-->
  12 + <!-- key="undefined"-->
  13 + <!-- label="全部"-->
  14 + <!-- value="undefined">-->
  15 + <!-- </el-option>-->
  16 + <!-- <el-option-->
  17 + <!-- v-for="item in mediaServerList"-->
  18 + <!-- :key="item"-->
  19 + <!-- :label="item"-->
  20 + <!-- :value="item">-->
  21 + <!-- </el-option>-->
  22 + <!-- </el-select>-->
  23 + <b>节点:</b> {{ mediaServerId }}
  24 + </div>
  25 + <div v-if="this.$route.params.mediaServerId" style="margin-right: 1rem;">
  26 + <span>流媒体:{{ this.$route.params.mediaServerId }}</span>
  27 + </div>
  28 + </div>
  29 + <el-container>
4 30 <el-aside width="260px">
5 31 <div class="record-list-box-box">
6 32 <div style="margin-top: 20px">
7   - <el-date-picker size="mini" style="width: 160px" v-model="chooseDate" :picker-options="pickerOptions" type="date" value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
8   - <el-button size="mini" type="primary" icon="fa fa-cloud-download" style="margin: auto; margin-left: 12px " title="裁剪合并" @click="drawerOpen"></el-button>
  33 + <el-date-picker size="mini" v-model="chooseDate" :picker-options="pickerOptions" type="date"
  34 + value-format="yyyy-MM-dd" placeholder="日期" @change="dateChange()"></el-date-picker>
  35 + <!-- <el-button :disabled="!mediaServerId" size="mini" type="primary" icon="fa fa-cloud-download" style="margin: auto; margin-left: 12px " title="裁剪合并" @click="drawerOpen"></el-button>-->
9 36 </div>
10 37 <div class="record-list-box" :style="recordListStyle">
11 38 <ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" >
12 39 <li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" >
13   - <el-tag v-if="choosedFile != item" @click="chooseFile(item)">
  40 + <el-tag v-if="choosedFile !== item.filename" @click="chooseFile(item)">
14 41 <i class="el-icon-video-camera" ></i>
15   - {{ item.substring(0,17)}}
  42 + {{ getFileShowName(item.fileName) }}
16 43 </el-tag>
17   - <el-tag type="danger" v-if="choosedFile == item">
  44 + <el-tag type="danger" v-if="choosedFile === item.filename">
18 45 <i class="el-icon-video-camera" ></i>
19   - {{ item.substring(0,17)}}
  46 + {{ getFileShowName(item.fileName) }}
20 47 </el-tag>
21   - <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;" :href="`${getFileBasePath()}/download.html?url=download/${recordFile.app}/${recordFile.stream}/${chooseDate}/${item}`" target="_blank" />
  48 + <a class="el-icon-download" style="color: #409EFF;font-weight: 600;margin-left: 10px;"
  49 + :href="`${getFileBasePath(item)}/download.html?url=download/${app}/${stream}/${chooseDate}/${item.fileName}`"
  50 + target="_blank"/>
22 51 </li>
23 52 </ul>
24 53 </div>
25   - <div v-if="detailFiles.length ==0" class="record-list-no-val" >暂无数据</div>
  54 + <div v-if="detailFiles.length === 0" class="record-list-no-val">暂无数据</div>
26 55 </div>
27 56  
28 57  
29 58 </el-aside>
30   - <el-main style="padding: 22px">
  59 + <el-main style="padding: 22px">
31 60 <div class="playBox" :style="playerStyle">
32 61 <player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player>
33 62 </div>
... ... @@ -48,8 +77,8 @@
48 77 </div>
49 78 </div>
50 79  
51   - </el-main>
52   - </el-container>
  80 + </el-main>
  81 + </el-container>
53 82 <el-drawer
54 83 title="录像下载"
55 84 :visible.sync="drawer"
... ... @@ -76,7 +105,8 @@
76 105 <li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index">
77 106 <div class="task-list-item-box" style="height: 2rem;line-height: 2rem;">
78 107 <span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span>
79   - <a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' + item.recordFile" target="_blank">
  108 + <a class="el-icon-download download-btn" :href="getFileBasePath() + '/download.html?url=download/' "
  109 + target="_blank">
80 110 </a>
81 111 </div>
82 112 </li>
... ... @@ -113,11 +143,16 @@
113 143 components: {
114 144 uiHeader, player
115 145 },
116   - props: ['recordFile', 'mediaServerId', 'dateFiles'],
  146 + // props: [ 'mediaServerId',],
117 147 data() {
118 148 return {
  149 + app: this.$route.params.app,
  150 + stream: this.$route.params.stream,
  151 + mediaServerId: this.$route.params.mediaServerId,
119 152 dateFilesObj: [],
  153 + mediaServerList: [],
120 154 detailFiles: [],
  155 + loading: false,
121 156 chooseDate: null,
122 157 videoUrl: null,
123 158 choosedFile: null,
... ... @@ -195,6 +230,9 @@
195 230 mounted() {
196 231 this.recordListStyle.height = this.winHeight + "px";
197 232 this.playerStyle["height"] = this.winHeight + "px";
  233 + console.log(this.app)
  234 + console.log(this.stream)
  235 + console.log(this.mediaServerId)
198 236 // 查询当年有视频的日期
199 237 this.getDateInYear(()=>{
200 238 if (Object.values(this.dateFilesObj).length > 0){
... ... @@ -216,7 +254,8 @@
216 254 let chooseFullDate = new Date(this.chooseDate +" " + this.timeFormat);
217 255 if (chooseFullDate.getFullYear() !== this.queryDate.getFullYear()
218 256 || chooseFullDate.getMonth() !== this.queryDate.getMonth()){
219   - // this.getDateInYear()
  257 + this.queryDate = chooseFullDate;
  258 + this.getDateInYear()
220 259 }
221 260 this.queryRecordDetails(()=>{
222 261 if (this.detailFiles.length > 0){
... ... @@ -242,48 +281,69 @@
242 281 }
243 282 },
244 283 queryRecordDetails: function (callback){
245   - let that = this;
246   - that.$axios({
  284 + this.$axios({
247 285 method: 'get',
248   - url:`/record_proxy/${that.mediaServerId}/api/record/file/list`,
  286 + url: `/api/cloud/record/list`,
249 287 params: {
250   - app: that.recordFile.app,
251   - stream: that.recordFile.stream,
252   - startTime: that.chooseDate + " 00:00:00",
253   - endTime: that.chooseDate + " 23:59:59",
254   - page: that.currentPage,
255   - count: that.count
  288 + app: this.app,
  289 + stream: this.stream,
  290 + startTime: this.chooseDate + " 00:00:00",
  291 + endTime: this.chooseDate + " 23:59:59",
  292 + page: this.currentPage,
  293 + count: this.count,
  294 + mediaServerId: this.mediaServerId
256 295 }
257   - }).then(function (res) {
  296 + }).then((res) => {
258 297 if (res.data.code === 0) {
259   - that.total = res.data.data.total;
260   - that.detailFiles = that.detailFiles.concat(res.data.data.list);
  298 + this.total = res.data.data.total;
  299 + this.detailFiles = this.detailFiles.concat(res.data.data.list);
  300 + let temp = new Set()
  301 + for (let i = 0; i < this.detailFiles.length; i++) {
  302 + temp.add(this.detailFiles[i].mediaServerId)
  303 + }
  304 + this.mediaServerList = Array.from(temp)
  305 + if (this.mediaServerList.length === 1) {
  306 + this.mediaServerId = this.mediaServerList[0]
  307 + }
261 308 }
262   - that.loading = false;
  309 + this.loading = false;
263 310 if (callback) callback();
264   - }).catch(function (error) {
  311 + }).catch((error) => {
265 312 console.log(error);
266   - that.loading = false;
  313 + this.loading = false;
267 314 });
268 315 },
269 316 chooseFile(file){
270   - this.choosedFile = file;
271 317 if (file == null) {
272 318 this.videoUrl = "";
  319 + this.choosedFile = "";
273 320 }else {
274   - this.videoUrl = `${this.getFileBasePath()}/download/${this.recordFile.app}/${this.recordFile.stream}/${this.chooseDate}/${this.choosedFile}`
275   -
  321 + this.choosedFile = file.fileName;
  322 + this.videoUrl = `${this.getFileBasePath(file)}/download/${this.app}/${this.stream}/${this.chooseDate}/${this.choosedFile}`
276 323 console.log(this.videoUrl)
277 324 }
278 325  
279 326 },
  327 + backToList() {
  328 + this.$router.back()
  329 + },
  330 + getFileShowName(name) {
  331 + return name.substring(0, 2) + ":" + name.substring(2, 4) + ":" + name.substring(4, 6) + "-" +
  332 + name.substring(7, 9) + ":" + name.substring(9, 11) + ":" + name.substring(11, 13)
  333 + },
  334 + chooseMediaChange() {
  335 +
  336 + },
  337 + getRecordList() {
280 338  
281   - getFileBasePath(){
  339 + },
  340 +
  341 + getFileBasePath(item) {
282 342 let basePath = ""
283 343 if (axios.defaults.baseURL.startsWith("http")) {
284   - basePath = `${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}`
  344 + basePath = `${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
285 345 }else {
286   - basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${this.mediaServerId}`
  346 + basePath = `${window.location.origin}${axios.defaults.baseURL}/record_proxy/${item.mediaServerId}`
287 347 }
288 348 return basePath;
289 349 },
... ... @@ -316,7 +376,7 @@
316 376 },
317 377 getTimeForFile(file){
318 378 console.log(file)
319   - let timeStr = file.substring(0,17);
  379 + let timeStr = file.fileName.substring(0, 17);
320 380 if(timeStr.indexOf("~") > 0){
321 381 timeStr = timeStr.replaceAll("-",":")
322 382 }
... ... @@ -370,27 +430,30 @@
370 430 });
371 431 },
372 432 getDateInYear(callback){
373   - let that = this;
374   - that.dateFilesObj = {};
  433 + this.dateFilesObj = {};
375 434 this.$axios({
376 435 method: 'get',
377   - url:`/record_proxy/${that.mediaServerId}/api/record/date/list`,
  436 + url: `/api/cloud/record/date/list`,
378 437 params: {
379   - app: that.recordFile.app,
380   - stream: that.recordFile.stream
  438 + app: this.app,
  439 + stream: this.stream,
  440 + year: this.queryDate.getFullYear(),
  441 + month: this.queryDate.getMonth() + 1,
  442 + mediaServerId: this.mediaServerId,
381 443 }
382   - }).then(function (res) {
  444 + }).then((res) => {
  445 + console.log(res)
383 446 if (res.data.code === 0) {
384 447 if (res.data.data.length > 0) {
385 448 for (let i = 0; i < res.data.data.length; i++) {
386   - that.dateFilesObj[res.data.data[i]] = res.data.data[i]
  449 + this.dateFilesObj[res.data.data[i]] = res.data.data[i]
387 450 }
388 451  
389   - console.log(that.dateFilesObj)
  452 + console.log(this.dateFilesObj)
390 453 }
391 454 }
392 455 if(callback)callback();
393   - }).catch(function (error) {
  456 + }).catch((error) => {
394 457 console.log(error);
395 458 });
396 459 },
... ... @@ -414,8 +477,8 @@
414 477 },
415 478 addTask(){
416 479 this.showTaskBox = true;
417   - let startTimeStr = this.chooseDate + " " + this.detailFiles[0].substring(0,8);
418   - let endTimeStr = this.chooseDate + " " + this.detailFiles[this.detailFiles.length - 1].substring(9,17);
  480 + let startTimeStr = this.chooseDate + " " + this.detailFiles[0].fileName.substring(0, 8);
  481 + let endTimeStr = this.chooseDate + " " + this.detailFiles[this.detailFiles.length - 1].fileName.substring(9, 17);
419 482 this.taskTimeRange[0] = new Date(startTimeStr)
420 483 this.taskTimeRange[1] = new Date(endTimeStr)
421 484 },
... ... @@ -425,8 +488,8 @@
425 488 method: 'get',
426 489 url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`,
427 490 params: {
428   - app: that.recordFile.app,
429   - stream: that.recordFile.stream,
  491 + app: that.app,
  492 + stream: that.stream,
430 493 startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
431 494 endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'),
432 495 }
... ...
web_src/src/components/DeviceList.vue 100644 → 100755
web_src/src/components/GBRecordDetail.vue 100644 → 100755
web_src/src/components/GeoConvertTools.js 100644 → 100755
web_src/src/components/Login.vue 100644 → 100755
web_src/src/components/MediaServerManger.vue 100644 → 100755
web_src/src/components/ParentPlatformList.vue 100644 → 100755
web_src/src/components/PushVideoList.vue 100644 → 100755
... ... @@ -89,6 +89,8 @@
89 89 <el-button size="medium" icon="el-icon-position" type="text" v-if="!!scope.row.gbId"
90 90 @click="removeFromGB(scope.row)">移出国标
91 91 </el-button>
  92 + <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像
  93 + </el-button>
92 94 </template>
93 95 </el-table-column>
94 96 </el-table>
... ... @@ -257,6 +259,10 @@ export default {
257 259 console.error(error);
258 260 });
259 261 },
  262 + queryCloudRecords: function (row) {
  263 +
  264 + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
  265 + },
260 266 importChannel: function () {
261 267 this.$refs.importChannel.openDialog(() => {
262 268  
... ...
web_src/src/components/StreamProxyList.vue 100644 → 100755
... ... @@ -91,6 +91,8 @@
91 91 <el-button size="medium" icon="el-icon-check" type="text" :loading="scope.row.startBtnLoading" v-if="!scope.row.enable" @click="start(scope.row)">启用</el-button>
92 92 <el-divider v-if="!scope.row.enable" direction="vertical"></el-divider>
93 93 <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c" @click="deleteStreamProxy(scope.row)">删除</el-button>
  94 + <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像
  95 + </el-button>
94 96 </template>
95 97 </el-table-column>
96 98 </el-table>
... ... @@ -243,6 +245,10 @@
243 245 });
244 246  
245 247 },
  248 + queryCloudRecords: function (row) {
  249 +
  250 + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
  251 + },
246 252 deleteStreamProxy: function(row){
247 253 let that = this;
248 254 this.$confirm('确定删除此代理吗?', '提示', {
... ...
web_src/src/components/UserManager.vue 100644 → 100755
web_src/src/components/channelList.vue 100644 → 100755
... ... @@ -105,6 +105,9 @@
105 105 <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider>
106 106 <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-camera" type="text" @click="queryRecords(scope.row)">设备录像
107 107 </el-button>
  108 + <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-cloudy"
  109 + type="text" @click="queryCloudRecords(scope.row)">云端录像
  110 + </el-button>
108 111 </template>
109 112 </el-table-column>
110 113 </el-table>
... ... @@ -283,6 +286,12 @@ export default {
283 286  
284 287 this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`)
285 288 },
  289 + queryCloudRecords: function (itemData) {
  290 + let deviceId = this.deviceId;
  291 + let channelId = itemData.channelId;
  292 +
  293 + this.$router.push(`/cloudRecordDetail/rtp/${deviceId}_${channelId}`)
  294 + },
286 295 stopDevicePush: function (itemData) {
287 296 var that = this;
288 297 this.$axios({
... ...
web_src/src/components/common/ h265web.vue 100644 → 100755
web_src/src/components/common/DeviceTree.vue 100644 → 100755
web_src/src/components/common/DeviceTreeForZtree.vue 100644 → 100755
web_src/src/components/common/MapComponent.vue 100644 → 100755
web_src/src/components/common/jessibuca.vue 100644 → 100755
web_src/src/components/console.vue 100644 → 100755
web_src/src/components/console/ConsoleCPU.vue 100644 → 100755
web_src/src/components/console/ConsoleDisk.vue 100644 → 100755
web_src/src/components/console/ConsoleMEM.vue 100644 → 100755
web_src/src/components/console/ConsoleMediaServer.vue 100644 → 100755
web_src/src/components/console/ConsoleNet.vue 100644 → 100755
web_src/src/components/console/ConsoleNodeLoad.vue 100644 → 100755
web_src/src/components/console/ConsoleResource.vue 100644 → 100755
web_src/src/components/dialog/MediaServerEdit.vue 100644 → 100755
web_src/src/components/dialog/StreamProxyEdit.vue 100644 → 100755
web_src/src/components/dialog/SyncChannelProgress.vue 100644 → 100755
web_src/src/components/dialog/catalogEdit.vue 100644 → 100755
web_src/src/components/dialog/changePassword.vue 100644 → 100755
web_src/src/components/dialog/changePasswordForAdmin.vue 100644 → 100755
web_src/src/components/dialog/changePushKey.vue 100644 → 100755
web_src/src/components/dialog/channelMapInfobox.vue 100644 → 100755
web_src/src/components/dialog/chooseChannel.vue 100644 → 100755
web_src/src/components/dialog/chooseChannelForCatalog.vue 100644 → 100755
web_src/src/components/dialog/chooseChannelForGb.vue 100644 → 100755
web_src/src/components/dialog/chooseChannelForStream.vue 100644 → 100755
web_src/src/components/dialog/configInfo.vue 100644 → 100755
web_src/src/components/dialog/deviceEdit.vue 100644 → 100755
web_src/src/components/dialog/devicePlayer.vue 100644 → 100755
web_src/src/components/dialog/easyPlayer.vue 100644 → 100755
web_src/src/components/dialog/getCatalog.vue 100644 → 100755
web_src/src/components/dialog/importChannel.vue 100644 → 100755
web_src/src/components/dialog/importChannelShowErrorData.vue 100644 → 100755
web_src/src/components/dialog/onvifEdit.vue 100644 → 100755
web_src/src/components/dialog/platformEdit.vue 100644 → 100755
web_src/src/components/dialog/pushStreamEdit.vue 100644 → 100755
web_src/src/components/dialog/queryTrace.vue 100644 → 100755
web_src/src/components/dialog/recordDownload.vue 100644 → 100755
web_src/src/components/dialog/rtcPlayer.vue 100644 → 100755
web_src/src/components/live.vue 100644 → 100755
web_src/src/components/map.vue 100644 → 100755
web_src/src/components/service/DeviceService.js 100644 → 100755
web_src/src/components/service/MediaServer.js 100644 → 100755
web_src/src/components/service/UserService.js 100644 → 100755
web_src/src/components/setting/Media.vue 100644 → 100755
web_src/src/components/setting/Sip.vue 100644 → 100755
web_src/src/components/setting/Web.vue 100644 → 100755
web_src/src/layout/UiHeader.vue 100644 → 100755
web_src/src/layout/index.vue 100644 → 100755
web_src/src/main.js 100644 → 100755
web_src/src/router/index.js 100644 → 100755
... ... @@ -12,6 +12,7 @@ import map from &#39;../components/map.vue&#39;
12 12 import login from '../components/Login.vue'
13 13 import parentPlatformList from '../components/ParentPlatformList.vue'
14 14 import cloudRecord from '../components/CloudRecord.vue'
  15 +import cloudRecordDetail from '../components/CloudRecordDetail.vue'
15 16 import mediaServerManger from '../components/MediaServerManger.vue'
16 17 import web from '../components/setting/Web.vue'
17 18 import sip from '../components/setting/Sip.vue'
... ... @@ -86,6 +87,16 @@ export default new VueRouter({
86 87 component: cloudRecord,
87 88 },
88 89 {
  90 + path: '/cloudRecordDetail/:app/:stream',
  91 + name: 'cloudRecordDetail',
  92 + component: cloudRecordDetail,
  93 + },
  94 + {
  95 + path: '/cloudRecordDetail/:mediaServerId/:app/:stream',
  96 + name: 'cloudRecordDetail',
  97 + component: cloudRecordDetail,
  98 + },
  99 + {
89 100 path: '/mediaServerManger',
90 101 name: 'mediaServerManger',
91 102 component: mediaServerManger,
... ...