Commit d0ef68af3fad9592c7bd9e61ed97244cd4a93e59

Authored by ChengHong
Committed by GitHub
2 parents bac19f58 9a64be46

Merge branch '648540858:wvp-28181-2.0' into wvp-28181-2.0

Showing 359 changed files with 5728 additions and 5183 deletions
doc/_content/introduction/config.md
@@ -153,7 +153,7 @@ user-settings: @@ -153,7 +153,7 @@ user-settings:
153 # 国标是否录制 153 # 国标是否录制
154 record-sip: true 154 record-sip: true
155 # 是否将日志存储进数据库 155 # 是否将日志存储进数据库
156 - logInDatebase: true 156 + logInDatabase: true
157 # 第三方匹配,用于从stream钟获取有效信息 157 # 第三方匹配,用于从stream钟获取有效信息
158 thirdPartyGBIdReg: [\s\S]* 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 -  
72 - public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";  
73 -  
74 -  
75 -  
76 -  
77 - //************************** redis 消息*********************************  
78 -  
79 - /**  
80 - * 流变化的通知  
81 - */  
82 - public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";  
83 -  
84 - /**  
85 - * 接收推流设备的GPS变化通知  
86 - */  
87 - public static final String VM_MSG_GPS = "VM_MSG_GPS";  
88 -  
89 - /**  
90 - * 接收推流设备的GPS变化通知  
91 - */  
92 - public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE";  
93 - /**  
94 - * 接收推流设备列表更新变化通知  
95 - */  
96 - public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE";  
97 -  
98 - /**  
99 - * redis 消息通知设备推流到平台  
100 - */  
101 - public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED";  
102 -  
103 - /**  
104 - * redis 消息通知上级平台开始观看流  
105 - */  
106 - public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY";  
107 -  
108 - /**  
109 - * redis 消息通知上级平台停止观看流  
110 - */  
111 - public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY";  
112 -  
113 - /**  
114 - * redis 消息接收关闭一个推流  
115 - */  
116 - public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED";  
117 -  
118 -  
119 - /**  
120 - * redis 消息通知平台通知设备推流结果  
121 - */  
122 - public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";  
123 -  
124 - /**  
125 - * redis 通知平台关闭推流  
126 - */  
127 - public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";  
128 -  
129 - /**  
130 - * redis 消息请求所有的在线通道  
131 - */  
132 - public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";  
133 -  
134 - /**  
135 - * 移动位置订阅通知  
136 - */  
137 - public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition";  
138 -  
139 - /**  
140 - * 报警订阅的通知(收到报警向redis发出通知)  
141 - */  
142 - public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm";  
143 -  
144 -  
145 - /**  
146 - * 报警通知的发送 (收到redis发出的通知,转发给其他平台)  
147 - */  
148 - public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive";  
149 -  
150 - /**  
151 - * 设备状态订阅的通知  
152 - */  
153 - public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device";  
154 -  
155 -  
156 - //************************** 第三方 ****************************************  
157 -  
158 - public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";  
159 - public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";  
160 - public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_";  
161 - public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_";  
162 - public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_";  
163 - public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_";  
164 -  
165 - /**  
166 - * Redis Const  
167 - * 设备录像信息结果前缀  
168 - */  
169 - public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";  
170 - /**  
171 - * Redis Const  
172 - * 设备录像信息结果前缀  
173 - */  
174 - public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";  
175 -  
176 -} 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 +
  72 + public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_";
  73 +
  74 +
  75 +
  76 +
  77 + //************************** redis 消息*********************************
  78 +
  79 + /**
  80 + * 流变化的通知
  81 + */
  82 + public static final String WVP_MSG_STREAM_CHANGE_PREFIX = "WVP_MSG_STREAM_CHANGE_";
  83 +
  84 + /**
  85 + * 接收推流设备的GPS变化通知
  86 + */
  87 + public static final String VM_MSG_GPS = "VM_MSG_GPS";
  88 +
  89 + /**
  90 + * 接收推流设备的GPS变化通知
  91 + */
  92 + public static final String VM_MSG_PUSH_STREAM_STATUS_CHANGE = "VM_MSG_PUSH_STREAM_STATUS_CHANGE";
  93 + /**
  94 + * 接收推流设备列表更新变化通知
  95 + */
  96 + public static final String VM_MSG_PUSH_STREAM_LIST_CHANGE = "VM_MSG_PUSH_STREAM_LIST_CHANGE";
  97 +
  98 + /**
  99 + * redis 消息通知设备推流到平台
  100 + */
  101 + public static final String VM_MSG_STREAM_PUSH_REQUESTED = "VM_MSG_STREAM_PUSH_REQUESTED";
  102 +
  103 + /**
  104 + * redis 消息通知上级平台开始观看流
  105 + */
  106 + public static final String VM_MSG_STREAM_START_PLAY_NOTIFY = "VM_MSG_STREAM_START_PLAY_NOTIFY";
  107 +
  108 + /**
  109 + * redis 消息通知上级平台停止观看流
  110 + */
  111 + public static final String VM_MSG_STREAM_STOP_PLAY_NOTIFY = "VM_MSG_STREAM_STOP_PLAY_NOTIFY";
  112 +
  113 + /**
  114 + * redis 消息接收关闭一个推流
  115 + */
  116 + public static final String VM_MSG_STREAM_PUSH_CLOSE_REQUESTED = "VM_MSG_STREAM_PUSH_CLOSE_REQUESTED";
  117 +
  118 +
  119 + /**
  120 + * redis 消息通知平台通知设备推流结果
  121 + */
  122 + public static final String VM_MSG_STREAM_PUSH_RESPONSE = "VM_MSG_STREAM_PUSH_RESPONSE";
  123 +
  124 + /**
  125 + * redis 通知平台关闭推流
  126 + */
  127 + public static final String VM_MSG_STREAM_PUSH_CLOSE = "VM_MSG_STREAM_PUSH_CLOSE";
  128 +
  129 + /**
  130 + * redis 消息请求所有的在线通道
  131 + */
  132 + public static final String VM_MSG_GET_ALL_ONLINE_REQUESTED = "VM_MSG_GET_ALL_ONLINE_REQUESTED";
  133 +
  134 + /**
  135 + * 移动位置订阅通知
  136 + */
  137 + public static final String VM_MSG_SUBSCRIBE_MOBILE_POSITION = "mobileposition";
  138 +
  139 + /**
  140 + * 报警订阅的通知(收到报警向redis发出通知)
  141 + */
  142 + public static final String VM_MSG_SUBSCRIBE_ALARM = "alarm";
  143 +
  144 +
  145 + /**
  146 + * 报警通知的发送 (收到redis发出的通知,转发给其他平台)
  147 + */
  148 + public static final String VM_MSG_SUBSCRIBE_ALARM_RECEIVE= "alarm_receive";
  149 +
  150 + /**
  151 + * 设备状态订阅的通知
  152 + */
  153 + public static final String VM_MSG_SUBSCRIBE_DEVICE_STATUS = "device";
  154 +
  155 +
  156 + //************************** 第三方 ****************************************
  157 +
  158 + public static final String WVP_STREAM_GB_ID_PREFIX = "memberNo_";
  159 + public static final String WVP_STREAM_GPS_MSG_PREFIX = "WVP_STREAM_GPS_MSG_";
  160 + public static final String WVP_OTHER_SEND_RTP_INFO = "VMP_OTHER_SEND_RTP_INFO_";
  161 + public static final String WVP_OTHER_SEND_PS_INFO = "VMP_OTHER_SEND_PS_INFO_";
  162 + public static final String WVP_OTHER_RECEIVE_RTP_INFO = "VMP_OTHER_RECEIVE_RTP_INFO_";
  163 + public static final String WVP_OTHER_RECEIVE_PS_INFO = "VMP_OTHER_RECEIVE_PS_INFO_";
  164 +
  165 + /**
  166 + * Redis Const
  167 + * 设备录像信息结果前缀
  168 + */
  169 + public static final String REDIS_RECORD_INFO_RES_PRE = "GB_RECORD_INFO_RES_";
  170 + /**
  171 + * Redis Const
  172 + * 设备录像信息结果前缀
  173 + */
  174 + public static final String REDIS_RECORD_INFO_RES_COUNT_PRE = "GB_RECORD_INFO_RES_COUNT:";
  175 +
  176 +}
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
@@ -51,7 +51,7 @@ public class ApiAccessFilter extends OncePerRequestFilter { @@ -51,7 +51,7 @@ public class ApiAccessFilter extends OncePerRequestFilter {
51 51
52 filterChain.doFilter(servletRequest, servletResponse); 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 LogDto logDto = new LogDto(); 56 LogDto logDto = new LogDto();
57 logDto.setName(uriName); 57 logDto.setName(uriName);
src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java
@@ -4,13 +4,19 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; @@ -4,13 +4,19 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; 4 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch;
5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; 5 import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform;
6 import com.genersoft.iot.vmp.service.IPlatformService; 6 import com.genersoft.iot.vmp.service.IPlatformService;
  7 +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
7 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 8 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
8 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 9 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  10 +import org.slf4j.Logger;
  11 +import org.slf4j.LoggerFactory;
9 import org.springframework.beans.factory.annotation.Autowired; 12 import org.springframework.beans.factory.annotation.Autowired;
10 import org.springframework.boot.CommandLineRunner; 13 import org.springframework.boot.CommandLineRunner;
11 import org.springframework.core.annotation.Order; 14 import org.springframework.core.annotation.Order;
12 import org.springframework.stereotype.Component; 15 import org.springframework.stereotype.Component;
13 16
  17 +import javax.sip.InvalidArgumentException;
  18 +import javax.sip.SipException;
  19 +import java.text.ParseException;
14 import java.util.List; 20 import java.util.List;
15 21
16 /** 22 /**
@@ -33,6 +39,7 @@ public class SipPlatformRunner implements CommandLineRunner { @@ -33,6 +39,7 @@ public class SipPlatformRunner implements CommandLineRunner {
33 @Autowired 39 @Autowired
34 private ISIPCommanderForPlatform sipCommanderForPlatform; 40 private ISIPCommanderForPlatform sipCommanderForPlatform;
35 41
  42 + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
36 43
37 @Override 44 @Override
38 public void run(String... args) throws Exception { 45 public void run(String... args) throws Exception {
@@ -50,9 +57,13 @@ public class SipPlatformRunner implements CommandLineRunner { @@ -50,9 +57,13 @@ public class SipPlatformRunner implements CommandLineRunner {
50 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch); 57 redisCatchStorage.updatePlatformCatchInfo(parentPlatformCatch);
51 if (parentPlatformCatchOld != null) { 58 if (parentPlatformCatchOld != null) {
52 // 取消订阅 59 // 取消订阅
53 - sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{  
54 - platformService.login(parentPlatform);  
55 - }); 60 + try {
  61 + sipCommanderForPlatform.unregister(parentPlatform, parentPlatformCatchOld.getSipTransactionInfo(), null, (eventResult)->{
  62 + platformService.login(parentPlatform);
  63 + });
  64 + } catch (InvalidArgumentException | ParseException | SipException e) {
  65 + logger.error("[命令发送失败] 国标级联 注销: {}", e.getMessage());
  66 + }
56 } 67 }
57 68
58 // 设置所有平台离线 69 // 设置所有平台离线
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -31,7 +31,7 @@ public class UserSetting { @@ -31,7 +31,7 @@ public class UserSetting {
31 31
32 private Boolean recordSip = Boolean.TRUE; 32 private Boolean recordSip = Boolean.TRUE;
33 33
34 - private Boolean logInDatebase = Boolean.TRUE; 34 + private Boolean logInDatabase = Boolean.TRUE;
35 35
36 private Boolean usePushingAsStatus = Boolean.TRUE; 36 private Boolean usePushingAsStatus = Boolean.TRUE;
37 37
@@ -132,12 +132,12 @@ public class UserSetting { @@ -132,12 +132,12 @@ public class UserSetting {
132 this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes; 132 this.interfaceAuthenticationExcludes = interfaceAuthenticationExcludes;
133 } 133 }
134 134
135 - public Boolean getLogInDatebase() {  
136 - return logInDatebase; 135 + public Boolean getLogInDatabase() {
  136 + return logInDatabase;
137 } 137 }
138 138
139 - public void setLogInDatebase(Boolean logInDatebase) {  
140 - this.logInDatebase = logInDatebase; 139 + public void setLogInDatabase(Boolean logInDatabase) {
  140 + this.logInDatabase = logInDatabase;
141 } 141 }
142 142
143 public String getServerId() { 143 public String getServerId() {
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
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,13 +12,19 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
12 import com.genersoft.iot.vmp.service.IDeviceService; 12 import com.genersoft.iot.vmp.service.IDeviceService;
13 import com.genersoft.iot.vmp.service.IMediaServerService; 13 import com.genersoft.iot.vmp.service.IMediaServerService;
14 import com.genersoft.iot.vmp.service.IPlatformService; 14 import com.genersoft.iot.vmp.service.IPlatformService;
  15 +import com.genersoft.iot.vmp.service.impl.PlatformServiceImpl;
15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 16 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
16 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 17 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  18 +import org.slf4j.Logger;
  19 +import org.slf4j.LoggerFactory;
17 import org.springframework.beans.factory.annotation.Autowired; 20 import org.springframework.beans.factory.annotation.Autowired;
18 import org.springframework.boot.CommandLineRunner; 21 import org.springframework.boot.CommandLineRunner;
19 import org.springframework.core.annotation.Order; 22 import org.springframework.core.annotation.Order;
20 import org.springframework.stereotype.Component; 23 import org.springframework.stereotype.Component;
21 24
  25 +import javax.sip.InvalidArgumentException;
  26 +import javax.sip.SipException;
  27 +import java.text.ParseException;
22 import java.util.HashMap; 28 import java.util.HashMap;
23 import java.util.List; 29 import java.util.List;
24 import java.util.Map; 30 import java.util.Map;
@@ -59,6 +65,8 @@ public class SipRunner implements CommandLineRunner { @@ -59,6 +65,8 @@ public class SipRunner implements CommandLineRunner {
59 @Autowired 65 @Autowired
60 private ISIPCommanderForPlatform commanderForPlatform; 66 private ISIPCommanderForPlatform commanderForPlatform;
61 67
  68 + private final static Logger logger = LoggerFactory.getLogger(PlatformServiceImpl.class);
  69 +
62 @Override 70 @Override
63 public void run(String... args) throws Exception { 71 public void run(String... args) throws Exception {
64 List<Device> deviceList = deviceService.getAllOnlineDevice(); 72 List<Device> deviceList = deviceService.getAllOnlineDevice();
@@ -110,7 +118,11 @@ public class SipRunner implements CommandLineRunner { @@ -110,7 +118,11 @@ public class SipRunner implements CommandLineRunner {
110 if (jsonObject != null && jsonObject.getInteger("code") == 0) { 118 if (jsonObject != null && jsonObject.getInteger("code") == 0) {
111 ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId()); 119 ParentPlatform platform = platformService.queryPlatformByServerGBId(sendRtpItem.getPlatformId());
112 if (platform != null) { 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.Device;  
6 -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;  
7 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
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.bean.SSRCInfo;  
11 -import gov.nist.javax.sip.message.SIPRequest;  
12 -  
13 -import javax.sip.InvalidArgumentException;  
14 -import javax.sip.SipException;  
15 -import java.text.ParseException;  
16 -  
17 -/**  
18 - * @description:设备能力接口,用于定义设备的控制、查询能力  
19 - * @author: swwheihei  
20 - * @date: 2020年5月3日 下午9:16:34  
21 - */  
22 -public interface ISIPCommander {  
23 -  
24 - /**  
25 - * 云台方向放控制,使用配置文件中的默认镜头移动速度  
26 - *  
27 - * @param device 控制设备  
28 - * @param channelId 预览通道  
29 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
30 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
31 - */  
32 - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException;  
33 -  
34 - /**  
35 - * 云台方向放控制  
36 - *  
37 - * @param device 控制设备  
38 - * @param channelId 预览通道  
39 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
40 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
41 - * @param moveSpeed 镜头移动速度  
42 - */  
43 - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;  
44 -  
45 - /**  
46 - * 云台缩放控制,使用配置文件中的默认镜头缩放速度  
47 - *  
48 - * @param device 控制设备  
49 - * @param channelId 预览通道  
50 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
51 - */  
52 - void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException;  
53 -  
54 - /**  
55 - * 云台缩放控制  
56 - *  
57 - * @param device 控制设备  
58 - * @param channelId 预览通道  
59 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
60 - */  
61 - void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;  
62 -  
63 - /**  
64 - * 云台控制,支持方向与缩放控制  
65 - *  
66 - * @param device 控制设备  
67 - * @param channelId 预览通道  
68 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
69 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
70 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
71 - * @param moveSpeed 镜头移动速度  
72 - * @param zoomSpeed 镜头缩放速度  
73 - */  
74 - void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException;  
75 -  
76 - /**  
77 - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令  
78 - *  
79 - * @param device 控制设备  
80 - * @param channelId 预览通道  
81 - * @param cmdCode 指令码  
82 - * @param parameter1 数据1  
83 - * @param parameter2 数据2  
84 - * @param combineCode2 组合码2  
85 - */  
86 - void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException;  
87 -  
88 - /**  
89 - * 前端控制指令(用于转发上级指令)  
90 - * @param device 控制设备  
91 - * @param channelId 预览通道  
92 - * @param cmdString 前端控制指令串  
93 - */  
94 - void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
95 -  
96 - /**  
97 - * 请求预览视频流  
98 - * @param device 视频设备  
99 - * @param channelId 预览通道  
100 - */  
101 - void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
102 -  
103 - /**  
104 - * 请求回放视频流  
105 - *  
106 - * @param device 视频设备  
107 - * @param channelId 预览通道  
108 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
109 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
110 - */  
111 - 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;  
112 -  
113 - /**  
114 - * 请求历史媒体下载  
115 - *  
116 - * @param device 视频设备  
117 - * @param channelId 预览通道  
118 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
119 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
120 - * @param downloadSpeed 下载倍速参数  
121 - */  
122 - void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
123 - String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,  
124 - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
125 -  
126 - /**  
127 - * 视频流停止  
128 - */  
129 - void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;  
130 -  
131 - void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;  
132 -  
133 - /**  
134 - * 回放暂停  
135 - */  
136 - void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;  
137 -  
138 - /**  
139 - * 回放恢复  
140 - */  
141 - void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;  
142 -  
143 - /**  
144 - * 回放拖动播放  
145 - */  
146 - void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException;  
147 -  
148 - /**  
149 - * 回放倍速播放  
150 - */  
151 - void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException;  
152 -  
153 - /**  
154 - * 回放控制  
155 - * @param device  
156 - * @param streamInfo  
157 - * @param content  
158 - */  
159 - void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;  
160 -  
161 -  
162 - /**  
163 - * 语音广播  
164 - *  
165 - * @param device 视频设备  
166 - * @param channelId 预览通道  
167 - */  
168 - void audioBroadcastCmd(Device device,String channelId);  
169 -  
170 - /**  
171 - * 语音广播  
172 - *  
173 - * @param device 视频设备  
174 - */  
175 - void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
176 - void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException;  
177 -  
178 - /**  
179 - * 音视频录像控制  
180 - *  
181 - * @param device 视频设备  
182 - * @param channelId 预览通道  
183 - * @param recordCmdStr 录像命令:Record / StopRecord  
184 - */  
185 - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
186 -  
187 - /**  
188 - * 远程启动控制命令  
189 - *  
190 - * @param device 视频设备  
191 - */  
192 - void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException;  
193 -  
194 - /**  
195 - * 报警布防/撤防命令  
196 - *  
197 - * @param device 视频设备  
198 - */  
199 - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
200 -  
201 - /**  
202 - * 报警复位命令  
203 - *  
204 - * @param device 视频设备  
205 - * @param alarmMethod 报警方式(可选)  
206 - * @param alarmType 报警类型(可选)  
207 - */  
208 - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
209 -  
210 - /**  
211 - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧  
212 - *  
213 - * @param device 视频设备  
214 - * @param channelId 预览通道  
215 - */  
216 - void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;  
217 -  
218 - /**  
219 - * 看守位控制命令  
220 - *  
221 - * @param device 视频设备  
222 - * @param channelId 通道id,非通道则是设备本身  
223 - * @param enabled 看守位使能:1 = 开启,0 = 关闭  
224 - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)  
225 - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255  
226 - */  
227 - void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;  
228 -  
229 - /**  
230 - * 设备配置命令  
231 - *  
232 - * @param device 视频设备  
233 - */  
234 - void deviceConfigCmd(Device device);  
235 -  
236 - /**  
237 - * 设备配置命令:basicParam  
238 - *  
239 - * @param device 视频设备  
240 - * @param channelId 通道编码(可选)  
241 - * @param name 设备/通道名称(可选)  
242 - * @param expiration 注册过期时间(可选)  
243 - * @param heartBeatInterval 心跳间隔时间(可选)  
244 - * @param heartBeatCount 心跳超时次数(可选)  
245 - */  
246 - void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
247 -  
248 - /**  
249 - * 查询设备状态  
250 - *  
251 - * @param device 视频设备  
252 - */  
253 - void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
254 -  
255 - /**  
256 - * 查询设备信息  
257 - *  
258 - * @param device 视频设备  
259 - * @return  
260 - */  
261 - void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException;  
262 -  
263 - /**  
264 - * 查询目录列表  
265 - *  
266 - * @param device 视频设备  
267 - */  
268 - void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException;  
269 -  
270 - /**  
271 - * 查询录像信息  
272 - *  
273 - * @param device 视频设备  
274 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
275 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
276 - * @param sn  
277 - */  
278 - void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
279 -  
280 - /**  
281 - * 查询报警信息  
282 - *  
283 - * @param device 视频设备  
284 - * @param startPriority 报警起始级别(可选)  
285 - * @param endPriority 报警终止级别(可选)  
286 - * @param alarmMethod 报警方式条件(可选)  
287 - * @param alarmType 报警类型  
288 - * @param startTime 报警发生起始时间(可选)  
289 - * @param endTime 报警发生终止时间(可选)  
290 - * @return true = 命令发送成功  
291 - */  
292 - void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,  
293 - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
294 -  
295 - /**  
296 - * 查询设备配置  
297 - *  
298 - * @param device 视频设备  
299 - * @param channelId 通道编码(可选)  
300 - * @param configType 配置类型:  
301 - */  
302 - void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
303 -  
304 - /**  
305 - * 查询设备预置位置  
306 - *  
307 - * @param device 视频设备  
308 - */  
309 - void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
310 -  
311 - /**  
312 - * 查询移动设备位置数据  
313 - *  
314 - * @param device 视频设备  
315 - */  
316 - void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
317 -  
318 - /**  
319 - * 订阅、取消订阅移动位置  
320 - *  
321 - * @param device 视频设备  
322 - * @return true = 命令发送成功  
323 - */  
324 - SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
325 -  
326 - /**  
327 - * 订阅、取消订阅报警信息  
328 - * @param device 视频设备  
329 - * @param expires 订阅过期时间(0 = 取消订阅)  
330 - * @param startPriority 报警起始级别(可选)  
331 - * @param endPriority 报警终止级别(可选)  
332 - * @param alarmType 报警类型  
333 - * @param startTime 报警发生起始时间(可选)  
334 - * @param endTime 报警发生终止时间(可选)  
335 - * @return true = 命令发送成功  
336 - */  
337 - void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException;  
338 -  
339 - /**  
340 - * 订阅、取消订阅目录信息  
341 - * @param device 视频设备  
342 - * @return true = 命令发送成功  
343 - */  
344 - SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;  
345 -  
346 - /**  
347 - * 拉框控制命令  
348 - *  
349 - * @param device 控制设备  
350 - * @param channelId 通道id  
351 - * @param cmdString 前端控制指令串  
352 - */  
353 - void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;  
354 -  
355 -  
356 - /**  
357 - * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待  
358 - * @param device 设备  
359 - * @param deviceAlarm 报警信息信息  
360 - * @return  
361 - */  
362 - void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;  
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.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  7 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  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.bean.SSRCInfo;
  11 +import gov.nist.javax.sip.message.SIPRequest;
  12 +
  13 +import javax.sip.InvalidArgumentException;
  14 +import javax.sip.SipException;
  15 +import java.text.ParseException;
  16 +
  17 +/**
  18 + * @description:设备能力接口,用于定义设备的控制、查询能力
  19 + * @author: swwheihei
  20 + * @date: 2020年5月3日 下午9:16:34
  21 + */
  22 +public interface ISIPCommander {
  23 +
  24 + /**
  25 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  26 + *
  27 + * @param device 控制设备
  28 + * @param channelId 预览通道
  29 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  30 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  31 + */
  32 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException;
  33 +
  34 + /**
  35 + * 云台方向放控制
  36 + *
  37 + * @param device 控制设备
  38 + * @param channelId 预览通道
  39 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  40 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  41 + * @param moveSpeed 镜头移动速度
  42 + */
  43 + void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
  44 +
  45 + /**
  46 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  47 + *
  48 + * @param device 控制设备
  49 + * @param channelId 预览通道
  50 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  51 + */
  52 + void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException;
  53 +
  54 + /**
  55 + * 云台缩放控制
  56 + *
  57 + * @param device 控制设备
  58 + * @param channelId 预览通道
  59 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  60 + */
  61 + void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException;
  62 +
  63 + /**
  64 + * 云台控制,支持方向与缩放控制
  65 + *
  66 + * @param device 控制设备
  67 + * @param channelId 预览通道
  68 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  69 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  70 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  71 + * @param moveSpeed 镜头移动速度
  72 + * @param zoomSpeed 镜头缩放速度
  73 + */
  74 + void ptzCmd(Device device,String channelId,int leftRight, int upDown, int inOut, int moveSpeed, int zoomSpeed) throws InvalidArgumentException, SipException, ParseException;
  75 +
  76 + /**
  77 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  78 + *
  79 + * @param device 控制设备
  80 + * @param channelId 预览通道
  81 + * @param cmdCode 指令码
  82 + * @param parameter1 数据1
  83 + * @param parameter2 数据2
  84 + * @param combineCode2 组合码2
  85 + */
  86 + void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException;
  87 +
  88 + /**
  89 + * 前端控制指令(用于转发上级指令)
  90 + * @param device 控制设备
  91 + * @param channelId 预览通道
  92 + * @param cmdString 前端控制指令串
  93 + */
  94 + void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  95 +
  96 + /**
  97 + * 请求预览视频流
  98 + * @param device 视频设备
  99 + * @param channelId 预览通道
  100 + */
  101 + void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId, ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  102 +
  103 + /**
  104 + * 请求回放视频流
  105 + *
  106 + * @param device 视频设备
  107 + * @param channelId 预览通道
  108 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  109 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  110 + */
  111 + 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;
  112 +
  113 + /**
  114 + * 请求历史媒体下载
  115 + *
  116 + * @param device 视频设备
  117 + * @param channelId 预览通道
  118 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  119 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  120 + * @param downloadSpeed 下载倍速参数
  121 + */
  122 + void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  123 + String startTime, String endTime, int downloadSpeed, ZlmHttpHookSubscribe.Event hookEvent,
  124 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  125 +
  126 + /**
  127 + * 视频流停止
  128 + */
  129 + void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException;
  130 +
  131 + void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException;
  132 +
  133 + /**
  134 + * 回放暂停
  135 + */
  136 + void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
  137 +
  138 + /**
  139 + * 回放恢复
  140 + */
  141 + void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException;
  142 +
  143 + /**
  144 + * 回放拖动播放
  145 + */
  146 + void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException;
  147 +
  148 + /**
  149 + * 回放倍速播放
  150 + */
  151 + void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException;
  152 +
  153 + /**
  154 + * 回放控制
  155 + * @param device
  156 + * @param streamInfo
  157 + * @param content
  158 + */
  159 + void playbackControlCmd(Device device, StreamInfo streamInfo, String content,SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException;
  160 +
  161 +
  162 + /**
  163 + * 语音广播
  164 + *
  165 + * @param device 视频设备
  166 + * @param channelId 预览通道
  167 + */
  168 + void audioBroadcastCmd(Device device,String channelId);
  169 +
  170 + /**
  171 + * 语音广播
  172 + *
  173 + * @param device 视频设备
  174 + */
  175 + void audioBroadcastCmd(Device device, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  176 + void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
  177 +
  178 + /**
  179 + * 音视频录像控制
  180 + *
  181 + * @param device 视频设备
  182 + * @param channelId 预览通道
  183 + * @param recordCmdStr 录像命令:Record / StopRecord
  184 + */
  185 + void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  186 +
  187 + /**
  188 + * 远程启动控制命令
  189 + *
  190 + * @param device 视频设备
  191 + */
  192 + void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException;
  193 +
  194 + /**
  195 + * 报警布防/撤防命令
  196 + *
  197 + * @param device 视频设备
  198 + */
  199 + void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  200 +
  201 + /**
  202 + * 报警复位命令
  203 + *
  204 + * @param device 视频设备
  205 + * @param alarmMethod 报警方式(可选)
  206 + * @param alarmType 报警类型(可选)
  207 + */
  208 + void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  209 +
  210 + /**
  211 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  212 + *
  213 + * @param device 视频设备
  214 + * @param channelId 预览通道
  215 + */
  216 + void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException;
  217 +
  218 + /**
  219 + * 看守位控制命令
  220 + *
  221 + * @param device 视频设备
  222 + * @param channelId 通道id,非通道则是设备本身
  223 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  224 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  225 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  226 + */
  227 + void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException;
  228 +
  229 + /**
  230 + * 设备配置命令
  231 + *
  232 + * @param device 视频设备
  233 + */
  234 + void deviceConfigCmd(Device device);
  235 +
  236 + /**
  237 + * 设备配置命令:basicParam
  238 + *
  239 + * @param device 视频设备
  240 + * @param channelId 通道编码(可选)
  241 + * @param name 设备/通道名称(可选)
  242 + * @param expiration 注册过期时间(可选)
  243 + * @param heartBeatInterval 心跳间隔时间(可选)
  244 + * @param heartBeatCount 心跳超时次数(可选)
  245 + */
  246 + void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  247 +
  248 + /**
  249 + * 查询设备状态
  250 + *
  251 + * @param device 视频设备
  252 + */
  253 + void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  254 +
  255 + /**
  256 + * 查询设备信息
  257 + *
  258 + * @param device 视频设备
  259 + * @return
  260 + */
  261 + void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException;
  262 +
  263 + /**
  264 + * 查询目录列表
  265 + *
  266 + * @param device 视频设备
  267 + */
  268 + void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException;
  269 +
  270 + /**
  271 + * 查询录像信息
  272 + *
  273 + * @param device 视频设备
  274 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  275 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  276 + * @param sn
  277 + */
  278 + void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer Secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  279 +
  280 + /**
  281 + * 查询报警信息
  282 + *
  283 + * @param device 视频设备
  284 + * @param startPriority 报警起始级别(可选)
  285 + * @param endPriority 报警终止级别(可选)
  286 + * @param alarmMethod 报警方式条件(可选)
  287 + * @param alarmType 报警类型
  288 + * @param startTime 报警发生起始时间(可选)
  289 + * @param endTime 报警发生终止时间(可选)
  290 + * @return true = 命令发送成功
  291 + */
  292 + void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod,
  293 + String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  294 +
  295 + /**
  296 + * 查询设备配置
  297 + *
  298 + * @param device 视频设备
  299 + * @param channelId 通道编码(可选)
  300 + * @param configType 配置类型:
  301 + */
  302 + void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  303 +
  304 + /**
  305 + * 查询设备预置位置
  306 + *
  307 + * @param device 视频设备
  308 + */
  309 + void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  310 +
  311 + /**
  312 + * 查询移动设备位置数据
  313 + *
  314 + * @param device 视频设备
  315 + */
  316 + void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  317 +
  318 + /**
  319 + * 订阅、取消订阅移动位置
  320 + *
  321 + * @param device 视频设备
  322 + * @return true = 命令发送成功
  323 + */
  324 + SIPRequest mobilePositionSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent , SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  325 +
  326 + /**
  327 + * 订阅、取消订阅报警信息
  328 + * @param device 视频设备
  329 + * @param expires 订阅过期时间(0 = 取消订阅)
  330 + * @param startPriority 报警起始级别(可选)
  331 + * @param endPriority 报警终止级别(可选)
  332 + * @param alarmType 报警类型
  333 + * @param startTime 报警发生起始时间(可选)
  334 + * @param endTime 报警发生终止时间(可选)
  335 + * @return true = 命令发送成功
  336 + */
  337 + void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException;
  338 +
  339 + /**
  340 + * 订阅、取消订阅目录信息
  341 + * @param device 视频设备
  342 + * @return true = 命令发送成功
  343 + */
  344 + SIPRequest catalogSubscribe(Device device, SIPRequest request, SipSubscribe.Event okEvent ,SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
  345 +
  346 + /**
  347 + * 拉框控制命令
  348 + *
  349 + * @param device 控制设备
  350 + * @param channelId 通道id
  351 + * @param cmdString 前端控制指令串
  352 + */
  353 + void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException;
  354 +
  355 +
  356 + /**
  357 + * 向设备发送报警NOTIFY消息, 用于互联结构下,此时将设备当成一个平级平台看待
  358 + * @param device 设备
  359 + * @param deviceAlarm 报警信息信息
  360 + * @return
  361 + */
  362 + void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException;
  363 +
  364 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java 100644 → 100755
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
1 -package com.genersoft.iot.vmp.gb28181.transmit.cmd;  
2 -  
3 -import com.genersoft.iot.vmp.conf.SipConfig;  
4 -import com.genersoft.iot.vmp.gb28181.SipLayer;  
5 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
6 -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;  
7 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
8 -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;  
9 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
10 -import com.genersoft.iot.vmp.utils.GitUtil;  
11 -import gov.nist.javax.sip.message.SIPRequest;  
12 -import gov.nist.javax.sip.message.SIPResponse;  
13 -import org.springframework.beans.factory.annotation.Autowired;  
14 -import org.springframework.stereotype.Component;  
15 -  
16 -import javax.sip.InvalidArgumentException;  
17 -import javax.sip.PeerUnavailableException;  
18 -import javax.sip.SipException;  
19 -import javax.sip.SipFactory;  
20 -import javax.sip.address.Address;  
21 -import javax.sip.address.SipURI;  
22 -import javax.sip.header.*;  
23 -import javax.sip.message.Request;  
24 -import java.text.ParseException;  
25 -import java.util.ArrayList;  
26 -  
27 -/**  
28 - * @description:摄像头命令request创造器 TODO 冗余代码太多待优化  
29 - * @author: swwheihei  
30 - * @date: 2020年5月6日 上午9:29:02  
31 - */  
32 -@Component  
33 -public class SIPRequestHeaderProvider {  
34 -  
35 - @Autowired  
36 - private SipConfig sipConfig;  
37 -  
38 - @Autowired  
39 - private SipLayer sipLayer;  
40 -  
41 - @Autowired  
42 - private GitUtil gitUtil;  
43 -  
44 - @Autowired  
45 - private IRedisCatchStorage redisCatchStorage;  
46 -  
47 - @Autowired  
48 - private VideoStreamSessionManager streamSession;  
49 -  
50 - public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
51 - Request request = null;  
52 - // sipuri  
53 - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
54 - // via  
55 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
56 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
57 - viaHeader.setRPort();  
58 - viaHeaders.add(viaHeader);  
59 - // from  
60 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
61 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
62 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);  
63 - // to  
64 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
65 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
66 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);  
67 -  
68 - // Forwards  
69 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
70 - // ceq  
71 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);  
72 -  
73 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,  
74 - toHeader, viaHeaders, maxForwards);  
75 -  
76 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
77 -  
78 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");  
79 - request.setContent(content, contentTypeHeader);  
80 - return request;  
81 - }  
82 -  
83 - public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
84 - Request request = null;  
85 - //请求行  
86 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
87 - //via  
88 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
89 - HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();  
90 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
91 - viaHeader.setRPort();  
92 - viaHeaders.add(viaHeader);  
93 -  
94 - //from  
95 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
96 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
97 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack  
98 - //to  
99 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
100 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
101 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);  
102 -  
103 - //Forwards  
104 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
105 -  
106 - //ceq  
107 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
108 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
109 -  
110 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
111 -  
112 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
113 - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
114 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
115 - // Subject  
116 - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));  
117 - request.addHeader(subjectHeader);  
118 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");  
119 - request.setContent(content, contentTypeHeader);  
120 - return request;  
121 - }  
122 -  
123 - public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
124 - Request request = null;  
125 - //请求行  
126 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
127 - // via  
128 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
129 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);  
130 - viaHeader.setRPort();  
131 - viaHeaders.add(viaHeader);  
132 - //from  
133 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
134 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
135 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack  
136 - //to  
137 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
138 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
139 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);  
140 -  
141 - //Forwards  
142 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
143 -  
144 - //ceq  
145 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);  
146 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
147 -  
148 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
149 - // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));  
150 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
151 -  
152 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
153 -  
154 - // Subject  
155 - SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));  
156 - request.addHeader(subjectHeader);  
157 -  
158 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");  
159 - request.setContent(content, contentTypeHeader);  
160 - return request;  
161 - }  
162 -  
163 - public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
164 - Request request = null;  
165 - //请求行  
166 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
167 - // via  
168 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
169 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());  
170 - viaHeaders.add(viaHeader);  
171 - //from  
172 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
173 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
174 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());  
175 - //to  
176 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
177 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
178 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());  
179 -  
180 - //Forwards  
181 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
182 -  
183 - //ceq  
184 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);  
185 - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
186 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
187 -  
188 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
189 -  
190 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
191 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
192 -  
193 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
194 -  
195 - return request;  
196 - }  
197 -  
198 - public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
199 - Request request = null;  
200 - // sipuri  
201 - SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
202 - // via  
203 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
204 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(),  
205 - device.getTransport(), SipUtils.getNewViaTag());  
206 - viaHeader.setRPort();  
207 - viaHeaders.add(viaHeader);  
208 - // from  
209 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());  
210 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
211 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());  
212 - // to  
213 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());  
214 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
215 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag());  
216 -  
217 - // Forwards  
218 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
219 -  
220 - // ceq  
221 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE);  
222 -  
223 - request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,  
224 - toHeader, viaHeaders, maxForwards);  
225 -  
226 -  
227 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
228 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
229 -  
230 - // Expires  
231 - ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);  
232 - request.addHeader(expireHeader);  
233 -  
234 - // Event  
235 - EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event);  
236 -  
237 - int random = (int) Math.floor(Math.random() * 10000);  
238 - eventHeader.setEventId(random + "");  
239 - request.addHeader(eventHeader);  
240 -  
241 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");  
242 - request.setContent(content, contentTypeHeader);  
243 -  
244 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
245 -  
246 - return request;  
247 - }  
248 -  
249 - public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo)  
250 - throws SipException, ParseException, InvalidArgumentException {  
251 - if (device == null || transactionInfo == null) {  
252 - return null;  
253 - }  
254 - SIPRequest request = null;  
255 - //请求行  
256 - SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());  
257 - // via  
258 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
259 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());  
260 - viaHeaders.add(viaHeader);  
261 - //from  
262 - SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());  
263 - Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);  
264 - FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());  
265 - //to  
266 - SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());  
267 - Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);  
268 - ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());  
269 -  
270 - //Forwards  
271 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
272 -  
273 - //ceq  
274 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);  
275 - CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());  
276 - request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);  
277 -  
278 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
279 -  
280 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));  
281 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
282 -  
283 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
284 -  
285 - if (content != null) {  
286 - ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application",  
287 - "MANSRTSP");  
288 - request.setContent(content, contentTypeHeader);  
289 - }  
290 - return request;  
291 - }  
292 -  
293 - public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException {  
294 -  
295 -  
296 - // via  
297 - ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();  
298 - ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());  
299 - viaHeaders.add(viaHeader);  
300 -  
301 - //Forwards  
302 - MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);  
303 -  
304 - //ceq  
305 - CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);  
306 -  
307 - Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);  
308 -  
309 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
310 -  
311 - Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));  
312 - request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));  
313 -  
314 - request.addHeader(SipUtils.createUserAgentHeader(gitUtil));  
315 -  
316 - return request;  
317 - }  
318 -} 1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd;
  2 +
  3 +import com.genersoft.iot.vmp.conf.SipConfig;
  4 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  5 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  6 +import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
  7 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  8 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  9 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  10 +import com.genersoft.iot.vmp.utils.GitUtil;
  11 +import gov.nist.javax.sip.message.SIPRequest;
  12 +import gov.nist.javax.sip.message.SIPResponse;
  13 +import org.springframework.beans.factory.annotation.Autowired;
  14 +import org.springframework.stereotype.Component;
  15 +
  16 +import javax.sip.InvalidArgumentException;
  17 +import javax.sip.PeerUnavailableException;
  18 +import javax.sip.SipException;
  19 +import javax.sip.SipFactory;
  20 +import javax.sip.address.Address;
  21 +import javax.sip.address.SipURI;
  22 +import javax.sip.header.*;
  23 +import javax.sip.message.Request;
  24 +import java.text.ParseException;
  25 +import java.util.ArrayList;
  26 +
  27 +/**
  28 + * @description:摄像头命令request创造器 TODO 冗余代码太多待优化
  29 + * @author: swwheihei
  30 + * @date: 2020年5月6日 上午9:29:02
  31 + */
  32 +@Component
  33 +public class SIPRequestHeaderProvider {
  34 +
  35 + @Autowired
  36 + private SipConfig sipConfig;
  37 +
  38 + @Autowired
  39 + private SipLayer sipLayer;
  40 +
  41 + @Autowired
  42 + private GitUtil gitUtil;
  43 +
  44 + @Autowired
  45 + private IRedisCatchStorage redisCatchStorage;
  46 +
  47 + @Autowired
  48 + private VideoStreamSessionManager streamSession;
  49 +
  50 + public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  51 + Request request = null;
  52 + // sipuri
  53 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  54 + // via
  55 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  56 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  57 + viaHeader.setRPort();
  58 + viaHeaders.add(viaHeader);
  59 + // from
  60 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  61 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  62 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag);
  63 + // to
  64 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  65 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  66 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, toTag);
  67 +
  68 + // Forwards
  69 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  70 + // ceq
  71 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.MESSAGE);
  72 +
  73 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
  74 + toHeader, viaHeaders, maxForwards);
  75 +
  76 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  77 +
  78 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  79 + request.setContent(content, contentTypeHeader);
  80 + return request;
  81 + }
  82 +
  83 + public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  84 + Request request = null;
  85 + //请求行
  86 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  87 + //via
  88 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  89 + HeaderFactory headerFactory = SipFactory.getInstance().createHeaderFactory();
  90 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  91 + viaHeader.setRPort();
  92 + viaHeaders.add(viaHeader);
  93 +
  94 + //from
  95 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  96 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  97 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  98 + //to
  99 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  100 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  101 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
  102 +
  103 + //Forwards
  104 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  105 +
  106 + //ceq
  107 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  108 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  109 +
  110 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  111 +
  112 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  113 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  114 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  115 + // Subject
  116 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
  117 + request.addHeader(subjectHeader);
  118 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  119 + request.setContent(content, contentTypeHeader);
  120 + return request;
  121 + }
  122 +
  123 + public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  124 + Request request = null;
  125 + //请求行
  126 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  127 + // via
  128 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  129 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
  130 + viaHeader.setRPort();
  131 + viaHeaders.add(viaHeader);
  132 + //from
  133 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  134 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  135 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
  136 + //to
  137 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  138 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  139 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
  140 +
  141 + //Forwards
  142 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  143 +
  144 + //ceq
  145 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INVITE);
  146 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INVITE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  147 +
  148 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  149 + // Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), device.getHost().getIp()+":"+device.getHost().getPort()));
  150 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  151 +
  152 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  153 +
  154 + // Subject
  155 + SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getId(), 0));
  156 + request.addHeader(subjectHeader);
  157 +
  158 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
  159 + request.setContent(content, contentTypeHeader);
  160 + return request;
  161 + }
  162 +
  163 + public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  164 + Request request = null;
  165 + //请求行
  166 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  167 + // via
  168 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  169 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  170 + viaHeaders.add(viaHeader);
  171 + //from
  172 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  173 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  174 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
  175 + //to
  176 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  177 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  178 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
  179 +
  180 + //Forwards
  181 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  182 +
  183 + //ceq
  184 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.BYE);
  185 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  186 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.BYE, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  187 +
  188 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  189 +
  190 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  191 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  192 +
  193 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  194 +
  195 + return request;
  196 + }
  197 +
  198 + public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  199 + Request request = null;
  200 + // sipuri
  201 + SipURI requestURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  202 + // via
  203 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  204 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(),
  205 + device.getTransport(), SipUtils.getNewViaTag());
  206 + viaHeader.setRPort();
  207 + viaHeaders.add(viaHeader);
  208 + // from
  209 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
  210 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  211 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());
  212 + // to
  213 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  214 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  215 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, requestOld == null ? null :requestOld.getToTag());
  216 +
  217 + // Forwards
  218 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  219 +
  220 + // ceq
  221 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.SUBSCRIBE);
  222 +
  223 + request = SipFactory.getInstance().createMessageFactory().createRequest(requestURI, Request.SUBSCRIBE, callIdHeader, cSeqHeader, fromHeader,
  224 + toHeader, viaHeaders, maxForwards);
  225 +
  226 +
  227 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  228 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  229 +
  230 + // Expires
  231 + ExpiresHeader expireHeader = SipFactory.getInstance().createHeaderFactory().createExpiresHeader(expires);
  232 + request.addHeader(expireHeader);
  233 +
  234 + // Event
  235 + EventHeader eventHeader = SipFactory.getInstance().createHeaderFactory().createEventHeader(event);
  236 +
  237 + int random = (int) Math.floor(Math.random() * 10000);
  238 + eventHeader.setEventId(random + "");
  239 + request.addHeader(eventHeader);
  240 +
  241 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  242 + request.setContent(content, contentTypeHeader);
  243 +
  244 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  245 +
  246 + return request;
  247 + }
  248 +
  249 + public SIPRequest createInfoRequest(Device device, String channelId, String content, SipTransactionInfo transactionInfo)
  250 + throws SipException, ParseException, InvalidArgumentException {
  251 + if (device == null || transactionInfo == null) {
  252 + return null;
  253 + }
  254 + SIPRequest request = null;
  255 + //请求行
  256 + SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress());
  257 + // via
  258 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  259 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
  260 + viaHeaders.add(viaHeader);
  261 + //from
  262 + SipURI fromSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
  263 + Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
  264 + FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
  265 + //to
  266 + SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress());
  267 + Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
  268 + ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag());
  269 +
  270 + //Forwards
  271 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  272 +
  273 + //ceq
  274 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(redisCatchStorage.getCSEQ(), Request.INFO);
  275 + CallIdHeader callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(transactionInfo.getCallId());
  276 + request = (SIPRequest)SipFactory.getInstance().createMessageFactory().createRequest(requestLine, Request.INFO, callIdHeader, cSeqHeader,fromHeader, toHeader, viaHeaders, maxForwards);
  277 +
  278 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  279 +
  280 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), sipLayer.getLocalIp(device.getLocalIp())+":"+sipConfig.getPort()));
  281 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  282 +
  283 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  284 +
  285 + if (content != null) {
  286 + ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("Application",
  287 + "MANSRTSP");
  288 + request.setContent(content, contentTypeHeader);
  289 + }
  290 + return request;
  291 + }
  292 +
  293 + public Request createAckRequest(String localIp, SipURI sipURI, SIPResponse sipResponse) throws ParseException, InvalidArgumentException, PeerUnavailableException {
  294 +
  295 +
  296 + // via
  297 + ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
  298 + ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(localIp, sipConfig.getPort(), sipResponse.getTopmostViaHeader().getTransport(), SipUtils.getNewViaTag());
  299 + viaHeaders.add(viaHeader);
  300 +
  301 + //Forwards
  302 + MaxForwardsHeader maxForwards = SipFactory.getInstance().createHeaderFactory().createMaxForwardsHeader(70);
  303 +
  304 + //ceq
  305 + CSeqHeader cSeqHeader = SipFactory.getInstance().createHeaderFactory().createCSeqHeader(sipResponse.getCSeqHeader().getSeqNumber(), Request.ACK);
  306 +
  307 + Request request = SipFactory.getInstance().createMessageFactory().createRequest(sipURI, Request.ACK, sipResponse.getCallIdHeader(), cSeqHeader, sipResponse.getFromHeader(), sipResponse.getToHeader(), viaHeaders, maxForwards);
  308 +
  309 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  310 +
  311 + Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(), localIp + ":"+sipConfig.getPort()));
  312 + request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
  313 +
  314 + request.addHeader(SipUtils.createUserAgentHeader(gitUtil));
  315 +
  316 + return request;
  317 + }
  318 +}
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java 100644 → 100755
1 -package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;  
2 -  
3 -import com.genersoft.iot.vmp.common.InviteSessionType;  
4 -import com.genersoft.iot.vmp.common.StreamInfo;  
5 -import com.genersoft.iot.vmp.conf.SipConfig;  
6 -import com.genersoft.iot.vmp.conf.UserSetting;  
7 -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;  
8 -import com.genersoft.iot.vmp.gb28181.SipLayer;  
9 -import com.genersoft.iot.vmp.gb28181.bean.Device;  
10 -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;  
11 -import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;  
12 -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;  
13 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
14 -import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;  
15 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;  
16 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;  
17 -import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;  
18 -import com.genersoft.iot.vmp.gb28181.utils.SipUtils;  
19 -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;  
20 -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;  
21 -import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;  
22 -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;  
23 -import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;  
24 -import com.genersoft.iot.vmp.service.IMediaServerService;  
25 -import com.genersoft.iot.vmp.service.bean.SSRCInfo;  
26 -import com.genersoft.iot.vmp.utils.DateUtil;  
27 -import gov.nist.javax.sip.message.SIPRequest;  
28 -import gov.nist.javax.sip.message.SIPResponse;  
29 -import org.slf4j.Logger;  
30 -import org.slf4j.LoggerFactory;  
31 -import org.springframework.beans.factory.annotation.Autowired;  
32 -import org.springframework.context.annotation.DependsOn;  
33 -import org.springframework.stereotype.Component;  
34 -import org.springframework.util.ObjectUtils;  
35 -  
36 -import javax.sip.InvalidArgumentException;  
37 -import javax.sip.ResponseEvent;  
38 -import javax.sip.SipException;  
39 -import javax.sip.SipFactory;  
40 -import javax.sip.header.CallIdHeader;  
41 -import javax.sip.message.Request;  
42 -import java.text.ParseException;  
43 -  
44 -/**  
45 - * @description:设备能力接口,用于定义设备的控制、查询能力  
46 - * @author: swwheihei  
47 - * @date: 2020年5月3日 下午9:22:48  
48 - */  
49 -@Component  
50 -@DependsOn("sipLayer")  
51 -public class SIPCommander implements ISIPCommander {  
52 -  
53 - private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);  
54 -  
55 - @Autowired  
56 - private SipConfig sipConfig;  
57 -  
58 - @Autowired  
59 - private SipLayer sipLayer;  
60 -  
61 - @Autowired  
62 - private SIPSender sipSender;  
63 -  
64 - @Autowired  
65 - private SIPRequestHeaderProvider headerProvider;  
66 -  
67 - @Autowired  
68 - private VideoStreamSessionManager streamSession;  
69 -  
70 - @Autowired  
71 - private UserSetting userSetting;  
72 -  
73 - @Autowired  
74 - private ZlmHttpHookSubscribe subscribe;  
75 -  
76 -  
77 -  
78 - @Autowired  
79 - private IMediaServerService mediaServerService;  
80 -  
81 -  
82 - /**  
83 - * 云台方向放控制,使用配置文件中的默认镜头移动速度  
84 - *  
85 - * @param device 控制设备  
86 - * @param channelId 预览通道  
87 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
88 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
89 - */  
90 - @Override  
91 - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException {  
92 - ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);  
93 - }  
94 -  
95 - /**  
96 - * 云台方向放控制  
97 - *  
98 - * @param device 控制设备  
99 - * @param channelId 预览通道  
100 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
101 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
102 - * @param moveSpeed 镜头移动速度  
103 - */  
104 - @Override  
105 - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException {  
106 - ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);  
107 - }  
108 -  
109 - /**  
110 - * 云台缩放控制,使用配置文件中的默认镜头缩放速度  
111 - *  
112 - * @param device 控制设备  
113 - * @param channelId 预览通道  
114 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
115 - */  
116 - @Override  
117 - public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException {  
118 - ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());  
119 - }  
120 -  
121 - /**  
122 - * 云台缩放控制  
123 - *  
124 - * @param device 控制设备  
125 - * @param channelId 预览通道  
126 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
127 - * @param zoomSpeed 镜头缩放速度  
128 - */  
129 - @Override  
130 - public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException {  
131 - ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);  
132 - }  
133 -  
134 - /**  
135 - * 云台指令码计算  
136 - *  
137 - * @param cmdCode 指令码  
138 - * @param parameter1 数据1  
139 - * @param parameter2 数据2  
140 - * @param combineCode2 组合码2  
141 - */  
142 - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {  
143 - StringBuilder builder = new StringBuilder("A50F01");  
144 - String strTmp;  
145 - strTmp = String.format("%02X", cmdCode);  
146 - builder.append(strTmp, 0, 2);  
147 - strTmp = String.format("%02X", parameter1);  
148 - builder.append(strTmp, 0, 2);  
149 - strTmp = String.format("%02X", parameter2);  
150 - builder.append(strTmp, 0, 2);  
151 - //优化zoom变倍速率  
152 - if ((combineCode2 > 0) && (combineCode2 <16))  
153 - {  
154 - combineCode2 = 16;  
155 - }  
156 - strTmp = String.format("%X", combineCode2);  
157 - builder.append(strTmp, 0, 1).append("0");  
158 - //计算校验码  
159 - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;  
160 - strTmp = String.format("%02X", checkCode);  
161 - builder.append(strTmp, 0, 2);  
162 - return builder.toString();  
163 - }  
164 -  
165 - /**  
166 - * 云台控制,支持方向与缩放控制  
167 - *  
168 - * @param device 控制设备  
169 - * @param channelId 预览通道  
170 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移  
171 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移  
172 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大  
173 - * @param moveSpeed 镜头移动速度  
174 - * @param zoomSpeed 镜头缩放速度  
175 - */  
176 - @Override  
177 - public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,  
178 - int zoomSpeed) throws InvalidArgumentException, SipException, ParseException {  
179 - String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);  
180 - StringBuilder ptzXml = new StringBuilder(200);  
181 - String charset = device.getCharset();  
182 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
183 - ptzXml.append("<Control>\r\n");  
184 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
185 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
186 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
187 - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");  
188 - ptzXml.append("<Info>\r\n");  
189 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
190 - ptzXml.append("</Info>\r\n");  
191 - ptzXml.append("</Control>\r\n");  
192 -  
193 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
194 -  
195 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
196 - }  
197 -  
198 - /**  
199 - * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令  
200 - *  
201 - * @param device 控制设备  
202 - * @param channelId 预览通道  
203 - * @param cmdCode 指令码  
204 - * @param parameter1 数据1  
205 - * @param parameter2 数据2  
206 - * @param combineCode2 组合码2  
207 - */  
208 - @Override  
209 - public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException {  
210 -  
211 - String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);  
212 - StringBuffer ptzXml = new StringBuffer(200);  
213 - String charset = device.getCharset();  
214 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
215 - ptzXml.append("<Control>\r\n");  
216 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
217 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
218 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
219 - ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");  
220 - ptzXml.append("<Info>\r\n");  
221 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
222 - ptzXml.append("</Info>\r\n");  
223 - ptzXml.append("</Control>\r\n");  
224 -  
225 -  
226 -  
227 -  
228 - SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
229 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
230 -  
231 - }  
232 -  
233 - /**  
234 - * 前端控制指令(用于转发上级指令)  
235 - *  
236 - * @param device 控制设备  
237 - * @param channelId 预览通道  
238 - * @param cmdString 前端控制指令串  
239 - */  
240 - @Override  
241 - public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
242 -  
243 - StringBuffer ptzXml = new StringBuffer(200);  
244 - String charset = device.getCharset();  
245 - ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
246 - ptzXml.append("<Control>\r\n");  
247 - ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
248 - ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
249 - ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
250 - ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");  
251 - ptzXml.append("<Info>\r\n");  
252 - ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");  
253 - ptzXml.append("</Info>\r\n");  
254 - ptzXml.append("</Control>\r\n");  
255 -  
256 -  
257 - Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
258 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent);  
259 -  
260 - }  
261 -  
262 - /**  
263 - * 请求预览视频流  
264 - *  
265 - * @param device 视频设备  
266 - * @param channelId 预览通道  
267 - * @param event hook订阅  
268 - * @param errorEvent sip错误订阅  
269 - */  
270 - @Override  
271 - public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
272 - ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
273 - String stream = ssrcInfo.getStream();  
274 -  
275 - if (device == null) {  
276 - return;  
277 - }  
278 -  
279 - logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
280 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());  
281 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {  
282 - if (event != null) {  
283 - event.response(mediaServerItemInUse, hookParam);  
284 - subscribe.removeSubscribe(hookSubscribe);  
285 - }  
286 - });  
287 - String sdpIp;  
288 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
289 - sdpIp = device.getSdpIp();  
290 - }else {  
291 - sdpIp = mediaServerItem.getSdpIp();  
292 - }  
293 - StringBuffer content = new StringBuffer(200);  
294 - content.append("v=0\r\n");  
295 - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");  
296 - content.append("s=Play\r\n");  
297 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
298 - content.append("t=0 0\r\n");  
299 -  
300 - if (userSetting.isSeniorSdp()) {  
301 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {  
302 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
303 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {  
304 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
305 - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {  
306 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
307 - }  
308 - content.append("a=recvonly\r\n");  
309 - content.append("a=rtpmap:96 PS/90000\r\n");  
310 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
311 - content.append("a=rtpmap:126 H264/90000\r\n");  
312 - content.append("a=rtpmap:125 H264S/90000\r\n");  
313 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
314 - content.append("a=rtpmap:99 H265/90000\r\n");  
315 - content.append("a=rtpmap:98 H264/90000\r\n");  
316 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
317 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式  
318 - content.append("a=setup:passive\r\n");  
319 - content.append("a=connection:new\r\n");  
320 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式  
321 - content.append("a=setup:active\r\n");  
322 - content.append("a=connection:new\r\n");  
323 - }  
324 - } else {  
325 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {  
326 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
327 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {  
328 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
329 - } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {  
330 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
331 - }  
332 - content.append("a=recvonly\r\n");  
333 - content.append("a=rtpmap:96 PS/90000\r\n");  
334 - content.append("a=rtpmap:98 H264/90000\r\n");  
335 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
336 - content.append("a=rtpmap:99 H265/90000\r\n");  
337 - if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式  
338 - content.append("a=setup:passive\r\n");  
339 - content.append("a=connection:new\r\n");  
340 - } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式  
341 - content.append("a=setup:active\r\n");  
342 - content.append("a=connection:new\r\n");  
343 - }  
344 - }  
345 -  
346 - if( device.isSwitchPrimarySubStream() ){  
347 - if("TP-LINK".equals(device.getManufacturer())){  
348 - if (device.isSwitchPrimarySubStream()){  
349 - content.append("a=streamMode:sub\r\n");  
350 - }else {  
351 - content.append("a=streamMode:main\r\n");  
352 - }  
353 - }else {  
354 - if (device.isSwitchPrimarySubStream()){  
355 - content.append("a=streamprofile:1\r\n");  
356 - }else {  
357 - content.append("a=streamprofile:0\r\n");  
358 - }  
359 - }  
360 - }  
361 -  
362 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc  
363 - // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率  
364 -// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备  
365 -  
366 -  
367 -  
368 - Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
369 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {  
370 - streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());  
371 - mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());  
372 - errorEvent.response(e);  
373 - }), e -> {  
374 - ResponseEvent responseEvent = (ResponseEvent) e.event;  
375 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
376 - streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,  
377 - InviteSessionType.PLAY);  
378 - okEvent.response(e);  
379 - });  
380 - }  
381 -  
382 - /**  
383 - * 请求回放视频流  
384 - *  
385 - * @param device 视频设备  
386 - * @param channelId 预览通道  
387 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
388 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
389 - */  
390 - @Override  
391 - public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
392 - String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,  
393 - SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
394 -  
395 -  
396 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
397 - String sdpIp;  
398 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
399 - sdpIp = device.getSdpIp();  
400 - }else {  
401 - sdpIp = mediaServerItem.getSdpIp();  
402 - }  
403 - StringBuffer content = new StringBuffer(200);  
404 - content.append("v=0\r\n");  
405 - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");  
406 - content.append("s=Playback\r\n");  
407 - content.append("u=" + channelId + ":0\r\n");  
408 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
409 - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "  
410 - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");  
411 -  
412 - String streamMode = device.getStreamMode();  
413 -  
414 - if (userSetting.isSeniorSdp()) {  
415 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
416 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
417 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
418 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
419 - } else if ("UDP".equalsIgnoreCase(streamMode)) {  
420 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
421 - }  
422 - content.append("a=recvonly\r\n");  
423 - content.append("a=rtpmap:96 PS/90000\r\n");  
424 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
425 - content.append("a=rtpmap:126 H264/90000\r\n");  
426 - content.append("a=rtpmap:125 H264S/90000\r\n");  
427 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
428 - content.append("a=rtpmap:99 H265/90000\r\n");  
429 - content.append("a=rtpmap:98 H264/90000\r\n");  
430 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
431 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式  
432 - content.append("a=setup:passive\r\n");  
433 - content.append("a=connection:new\r\n");  
434 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式  
435 - content.append("a=setup:active\r\n");  
436 - content.append("a=connection:new\r\n");  
437 - }  
438 - } else {  
439 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
440 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
441 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
442 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
443 - } else if ("UDP".equalsIgnoreCase(streamMode)) {  
444 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
445 - }  
446 - content.append("a=recvonly\r\n");  
447 - content.append("a=rtpmap:96 PS/90000\r\n");  
448 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
449 - content.append("a=rtpmap:98 H264/90000\r\n");  
450 - content.append("a=rtpmap:99 H265/90000\r\n");  
451 - if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {  
452 - // tcp被动模式  
453 - content.append("a=setup:passive\r\n");  
454 - content.append("a=connection:new\r\n");  
455 - } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {  
456 - // tcp主动模式  
457 - content.append("a=setup:active\r\n");  
458 - content.append("a=connection:new\r\n");  
459 - }  
460 - }  
461 -  
462 - //ssrc  
463 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");  
464 -  
465 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
466 - // 添加订阅  
467 - subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {  
468 - if (hookEvent != null) {  
469 - hookEvent.response(mediaServerItemInUse, hookParam);  
470 - }  
471 - subscribe.removeSubscribe(hookSubscribe);  
472 - });  
473 - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());  
474 -  
475 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {  
476 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
477 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
478 - streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);  
479 - okEvent.response(event);  
480 - });  
481 - }  
482 -  
483 - /**  
484 - * 请求历史媒体下载  
485 - *  
486 - * @param device 视频设备  
487 - * @param channelId 预览通道  
488 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
489 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
490 - * @param downloadSpeed 下载倍速参数  
491 - */  
492 - @Override  
493 - public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,  
494 - String startTime, String endTime, int downloadSpeed,  
495 - ZlmHttpHookSubscribe.Event hookEvent,  
496 - SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
497 -  
498 - logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());  
499 - String sdpIp;  
500 - if (!ObjectUtils.isEmpty(device.getSdpIp())) {  
501 - sdpIp = device.getSdpIp();  
502 - }else {  
503 - sdpIp = mediaServerItem.getSdpIp();  
504 - }  
505 - StringBuffer content = new StringBuffer(200);  
506 - content.append("v=0\r\n");  
507 - content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");  
508 - content.append("s=Download\r\n");  
509 - content.append("u=" + channelId + ":0\r\n");  
510 - content.append("c=IN IP4 " + sdpIp + "\r\n");  
511 - content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "  
512 - + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");  
513 -  
514 - String streamMode = device.getStreamMode().toUpperCase();  
515 -  
516 - if (userSetting.isSeniorSdp()) {  
517 - if ("TCP-PASSIVE".equals(streamMode)) {  
518 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
519 - } else if ("TCP-ACTIVE".equals(streamMode)) {  
520 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");  
521 - } else if ("UDP".equals(streamMode)) {  
522 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");  
523 - }  
524 - content.append("a=recvonly\r\n");  
525 - content.append("a=rtpmap:96 PS/90000\r\n");  
526 - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");  
527 - content.append("a=rtpmap:126 H264/90000\r\n");  
528 - content.append("a=rtpmap:125 H264S/90000\r\n");  
529 - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");  
530 - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");  
531 - content.append("a=fmtp:99 profile-level-id=3\r\n");  
532 - content.append("a=rtpmap:98 H264/90000\r\n");  
533 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
534 - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式  
535 - content.append("a=setup:passive\r\n");  
536 - content.append("a=connection:new\r\n");  
537 - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式  
538 - content.append("a=setup:active\r\n");  
539 - content.append("a=connection:new\r\n");  
540 - }  
541 - } else {  
542 - if ("TCP-PASSIVE".equals(streamMode)) {  
543 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
544 - } else if ("TCP-ACTIVE".equals(streamMode)) {  
545 - content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");  
546 - } else if ("UDP".equals(streamMode)) {  
547 - content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");  
548 - }  
549 - content.append("a=recvonly\r\n");  
550 - content.append("a=rtpmap:96 PS/90000\r\n");  
551 - content.append("a=rtpmap:97 MPEG4/90000\r\n");  
552 - content.append("a=rtpmap:98 H264/90000\r\n");  
553 - content.append("a=rtpmap:99 H265/90000\r\n");  
554 - if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式  
555 - content.append("a=setup:passive\r\n");  
556 - content.append("a=connection:new\r\n");  
557 - } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式  
558 - content.append("a=setup:active\r\n");  
559 - content.append("a=connection:new\r\n");  
560 - }  
561 - }  
562 - content.append("a=downloadspeed:" + downloadSpeed + "\r\n");  
563 -  
564 - content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc  
565 - logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());  
566 - HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());  
567 - // 添加订阅  
568 - CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());  
569 - String callId= newCallIdHeader.getCallId();  
570 - subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {  
571 - logger.debug("sipc 添加订阅===callId {}",callId);  
572 - hookEvent.response(mediaServerItemInUse, hookParam);  
573 - subscribe.removeSubscribe(hookSubscribe);  
574 - hookSubscribe.getContent().put("regist", false);  
575 - hookSubscribe.getContent().put("schema", "rtsp");  
576 - // 添加流注销的订阅,注销了后向设备发送bye  
577 - subscribe.addSubscribe(hookSubscribe,  
578 - (mediaServerItemForEnd, hookParam1) -> {  
579 - logger.info("[录像]下载结束, 发送BYE");  
580 - try {  
581 - streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);  
582 - } catch (InvalidArgumentException | ParseException | SipException |  
583 - SsrcTransactionNotFoundException e) {  
584 - logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());  
585 - }  
586 - });  
587 - });  
588 -  
589 - Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());  
590 -  
591 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {  
592 - ResponseEvent responseEvent = (ResponseEvent) event.event;  
593 - SIPResponse response = (SIPResponse) responseEvent.getResponse();  
594 - String contentString =new String(response.getRawContent());  
595 - String ssrc = SipUtils.getSsrcFromSdp(contentString);  
596 - streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);  
597 - okEvent.response(event);  
598 - });  
599 - }  
600 -  
601 - /**  
602 - * 视频流停止, 不使用回调  
603 - */  
604 - @Override  
605 - public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException {  
606 - streamByeCmd(device, channelId, stream, callId, null);  
607 - }  
608 -  
609 - /**  
610 - * 视频流停止  
611 - */  
612 - @Override  
613 - public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {  
614 - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream);  
615 - if (ssrcTransaction == null) {  
616 - throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);  
617 - }  
618 -  
619 - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());  
620 - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());  
621 - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());  
622 -  
623 - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());  
624 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);  
625 - }  
626 -  
627 - /**  
628 - * 语音广播  
629 - *  
630 - * @param device 视频设备  
631 - * @param channelId 预览通道  
632 - */  
633 - @Override  
634 - public void audioBroadcastCmd(Device device, String channelId) {  
635 - }  
636 -  
637 - /**  
638 - * 语音广播  
639 - *  
640 - * @param device 视频设备  
641 - */  
642 - @Override  
643 - public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException {  
644 -  
645 - StringBuffer broadcastXml = new StringBuffer(200);  
646 - String charset = device.getCharset();  
647 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
648 - broadcastXml.append("<Notify>\r\n");  
649 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
650 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
651 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
652 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
653 - broadcastXml.append("</Notify>\r\n");  
654 -  
655 -  
656 -  
657 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
658 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
659 -  
660 - }  
661 -  
662 - @Override  
663 - public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
664 -  
665 - StringBuffer broadcastXml = new StringBuffer(200);  
666 - String charset = device.getCharset();  
667 - broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
668 - broadcastXml.append("<Notify>\r\n");  
669 - broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");  
670 - broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
671 - broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");  
672 - broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");  
673 - broadcastXml.append("</Notify>\r\n");  
674 -  
675 -  
676 -  
677 - Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
678 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
679 -  
680 - }  
681 -  
682 -  
683 - /**  
684 - * 音视频录像控制  
685 - *  
686 - * @param device 视频设备  
687 - * @param channelId 预览通道  
688 - * @param recordCmdStr 录像命令:Record / StopRecord  
689 - */  
690 - @Override  
691 - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
692 - StringBuffer cmdXml = new StringBuffer(200);  
693 - String charset = device.getCharset();  
694 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
695 - cmdXml.append("<Control>\r\n");  
696 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
697 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
698 - if (ObjectUtils.isEmpty(channelId)) {  
699 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
700 - } else {  
701 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
702 - }  
703 - cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");  
704 - cmdXml.append("</Control>\r\n");  
705 -  
706 -  
707 -  
708 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
709 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
710 - }  
711 -  
712 - /**  
713 - * 远程启动控制命令  
714 - *  
715 - * @param device 视频设备  
716 - */  
717 - @Override  
718 - public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException {  
719 -  
720 - StringBuffer cmdXml = new StringBuffer(200);  
721 - String charset = device.getCharset();  
722 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
723 - cmdXml.append("<Control>\r\n");  
724 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
725 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
726 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
727 - cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");  
728 - cmdXml.append("</Control>\r\n");  
729 -  
730 -  
731 -  
732 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
733 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
734 - }  
735 -  
736 - /**  
737 - * 报警布防/撤防命令  
738 - *  
739 - * @param device 视频设备  
740 - * @param guardCmdStr "SetGuard"/"ResetGuard"  
741 - */  
742 - @Override  
743 - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
744 -  
745 - StringBuffer cmdXml = new StringBuffer(200);  
746 - String charset = device.getCharset();  
747 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
748 - cmdXml.append("<Control>\r\n");  
749 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
750 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
751 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
752 - cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");  
753 - cmdXml.append("</Control>\r\n");  
754 -  
755 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
756 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
757 - }  
758 -  
759 - /**  
760 - * 报警复位命令  
761 - *  
762 - * @param device 视频设备  
763 - */  
764 - @Override  
765 - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
766 -  
767 - StringBuffer cmdXml = new StringBuffer(200);  
768 - String charset = device.getCharset();  
769 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
770 - cmdXml.append("<Control>\r\n");  
771 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
772 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
773 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
774 - cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");  
775 - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {  
776 - cmdXml.append("<Info>\r\n");  
777 - }  
778 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
779 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
780 - }  
781 - if (!ObjectUtils.isEmpty(alarmType)) {  
782 - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");  
783 - }  
784 - if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {  
785 - cmdXml.append("</Info>\r\n");  
786 - }  
787 - cmdXml.append("</Control>\r\n");  
788 -  
789 -  
790 -  
791 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
792 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
793 - }  
794 -  
795 - /**  
796 - * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧  
797 - *  
798 - * @param device 视频设备  
799 - * @param channelId 预览通道  
800 - */  
801 - @Override  
802 - public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException {  
803 -  
804 - StringBuffer cmdXml = new StringBuffer(200);  
805 - String charset = device.getCharset();  
806 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
807 - cmdXml.append("<Control>\r\n");  
808 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
809 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
810 - if (ObjectUtils.isEmpty(channelId)) {  
811 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
812 - } else {  
813 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
814 - }  
815 - cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");  
816 - cmdXml.append("</Control>\r\n");  
817 -  
818 -  
819 -  
820 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
821 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
822 - }  
823 -  
824 - /**  
825 - * 看守位控制命令  
826 - *  
827 - * @param device 视频设备  
828 - * @param channelId 通道id,非通道则是设备本身  
829 - * @param enabled 看守位使能:1 = 开启,0 = 关闭  
830 - * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)  
831 - * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255  
832 - */  
833 - @Override  
834 - public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {  
835 -  
836 - StringBuffer cmdXml = new StringBuffer(200);  
837 - String charset = device.getCharset();  
838 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
839 - cmdXml.append("<Control>\r\n");  
840 - cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
841 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
842 - if (ObjectUtils.isEmpty(channelId)) {  
843 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
844 - } else {  
845 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
846 - }  
847 - cmdXml.append("<HomePosition>\r\n");  
848 - if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {  
849 - cmdXml.append("<Enabled>1</Enabled>\r\n");  
850 - if (NumericUtil.isInteger(resetTime)) {  
851 - cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");  
852 - } else {  
853 - cmdXml.append("<ResetTime>0</ResetTime>\r\n");  
854 - }  
855 - if (NumericUtil.isInteger(presetIndex)) {  
856 - cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");  
857 - } else {  
858 - cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");  
859 - }  
860 - } else {  
861 - cmdXml.append("<Enabled>0</Enabled>\r\n");  
862 - }  
863 - cmdXml.append("</HomePosition>\r\n");  
864 - cmdXml.append("</Control>\r\n");  
865 -  
866 -  
867 -  
868 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
869 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);  
870 - }  
871 -  
872 - /**  
873 - * 设备配置命令  
874 - *  
875 - * @param device 视频设备  
876 - */  
877 - @Override  
878 - public void deviceConfigCmd(Device device) {  
879 - // TODO Auto-generated method stub  
880 - }  
881 -  
882 - /**  
883 - * 设备配置命令:basicParam  
884 - *  
885 - * @param device 视频设备  
886 - * @param channelId 通道编码(可选)  
887 - * @param name 设备/通道名称(可选)  
888 - * @param expiration 注册过期时间(可选)  
889 - * @param heartBeatInterval 心跳间隔时间(可选)  
890 - * @param heartBeatCount 心跳超时次数(可选)  
891 - */  
892 - @Override  
893 - public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,  
894 - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
895 -  
896 - StringBuffer cmdXml = new StringBuffer(200);  
897 - String charset = device.getCharset();  
898 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
899 - cmdXml.append("<Control>\r\n");  
900 - cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");  
901 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
902 - if (ObjectUtils.isEmpty(channelId)) {  
903 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
904 - } else {  
905 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
906 - }  
907 - cmdXml.append("<BasicParam>\r\n");  
908 - if (!ObjectUtils.isEmpty(name)) {  
909 - cmdXml.append("<Name>" + name + "</Name>\r\n");  
910 - }  
911 - if (NumericUtil.isInteger(expiration)) {  
912 - if (Integer.valueOf(expiration) > 0) {  
913 - cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");  
914 - }  
915 - }  
916 - if (NumericUtil.isInteger(heartBeatInterval)) {  
917 - if (Integer.valueOf(heartBeatInterval) > 0) {  
918 - cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");  
919 - }  
920 - }  
921 - if (NumericUtil.isInteger(heartBeatCount)) {  
922 - if (Integer.valueOf(heartBeatCount) > 0) {  
923 - cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");  
924 - }  
925 - }  
926 - cmdXml.append("</BasicParam>\r\n");  
927 - cmdXml.append("</Control>\r\n");  
928 -  
929 -  
930 -  
931 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
932 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
933 - }  
934 -  
935 - /**  
936 - * 查询设备状态  
937 - *  
938 - * @param device 视频设备  
939 - */  
940 - @Override  
941 - public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
942 -  
943 - String charset = device.getCharset();  
944 - StringBuffer catalogXml = new StringBuffer(200);  
945 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
946 - catalogXml.append("<Query>\r\n");  
947 - catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");  
948 - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
949 - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
950 - catalogXml.append("</Query>\r\n");  
951 -  
952 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
953 -  
954 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
955 - }  
956 -  
957 - /**  
958 - * 查询设备信息  
959 - *  
960 - * @param device 视频设备  
961 - */  
962 - @Override  
963 - public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {  
964 -  
965 - StringBuffer catalogXml = new StringBuffer(200);  
966 - String charset = device.getCharset();  
967 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
968 - catalogXml.append("<Query>\r\n");  
969 - catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");  
970 - catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
971 - catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
972 - catalogXml.append("</Query>\r\n");  
973 -  
974 -  
975 -  
976 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
977 -  
978 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
979 -  
980 - }  
981 -  
982 - /**  
983 - * 查询目录列表  
984 - *  
985 - * @param device 视频设备  
986 - */  
987 - @Override  
988 - public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException {  
989 -  
990 - StringBuffer catalogXml = new StringBuffer(200);  
991 - String charset = device.getCharset();  
992 - catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
993 - catalogXml.append("<Query>\r\n");  
994 - catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");  
995 - catalogXml.append(" <SN>" + sn + "</SN>\r\n");  
996 - catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
997 - catalogXml.append("</Query>\r\n");  
998 -  
999 -  
1000 -  
1001 - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1002 -  
1003 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1004 - }  
1005 -  
1006 - /**  
1007 - * 查询录像信息  
1008 - *  
1009 - * @param device 视频设备  
1010 - * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss  
1011 - * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss  
1012 - */  
1013 - @Override  
1014 - public void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1015 - if (secrecy == null) {  
1016 - secrecy = 0;  
1017 - }  
1018 - if (type == null) {  
1019 - type = "all";  
1020 - }  
1021 -  
1022 - StringBuffer recordInfoXml = new StringBuffer(200);  
1023 - String charset = device.getCharset();  
1024 - recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1025 - recordInfoXml.append("<Query>\r\n");  
1026 - recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");  
1027 - recordInfoXml.append("<SN>" + sn + "</SN>\r\n");  
1028 - recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1029 - if (startTime != null) {  
1030 - recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");  
1031 - }  
1032 - if (endTime != null) {  
1033 - recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");  
1034 - }  
1035 - if (secrecy != null) {  
1036 - recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n");  
1037 - }  
1038 - if (type != null) {  
1039 - // 大华NVR要求必须增加一个值为all的文本元素节点Type  
1040 - recordInfoXml.append("<Type>" + type + "</Type>\r\n");  
1041 - }  
1042 - recordInfoXml.append("</Query>\r\n");  
1043 -  
1044 -  
1045 -  
1046 - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),  
1047 - SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1048 -  
1049 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1050 - }  
1051 -  
1052 - /**  
1053 - * 查询报警信息  
1054 - *  
1055 - * @param device 视频设备  
1056 - * @param startPriority 报警起始级别(可选)  
1057 - * @param endPriority 报警终止级别(可选)  
1058 - * @param alarmMethod 报警方式条件(可选)  
1059 - * @param alarmType 报警类型  
1060 - * @param startTime 报警发生起始时间(可选)  
1061 - * @param endTime 报警发生终止时间(可选)  
1062 - * @return true = 命令发送成功  
1063 - */  
1064 - @Override  
1065 - public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,  
1066 - String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1067 -  
1068 - StringBuffer cmdXml = new StringBuffer(200);  
1069 - String charset = device.getCharset();  
1070 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1071 - cmdXml.append("<Query>\r\n");  
1072 - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");  
1073 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1074 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1075 - if (!ObjectUtils.isEmpty(startPriority)) {  
1076 - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");  
1077 - }  
1078 - if (!ObjectUtils.isEmpty(endPriority)) {  
1079 - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");  
1080 - }  
1081 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
1082 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
1083 - }  
1084 - if (!ObjectUtils.isEmpty(alarmType)) {  
1085 - cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");  
1086 - }  
1087 - if (!ObjectUtils.isEmpty(startTime)) {  
1088 - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");  
1089 - }  
1090 - if (!ObjectUtils.isEmpty(endTime)) {  
1091 - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");  
1092 - }  
1093 - cmdXml.append("</Query>\r\n");  
1094 -  
1095 -  
1096 -  
1097 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1098 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1099 - }  
1100 -  
1101 - /**  
1102 - * 查询设备配置  
1103 - *  
1104 - * @param device 视频设备  
1105 - * @param channelId 通道编码(可选)  
1106 - * @param configType 配置类型:  
1107 - */  
1108 - @Override  
1109 - public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1110 -  
1111 - StringBuffer cmdXml = new StringBuffer(200);  
1112 - String charset = device.getCharset();  
1113 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1114 - cmdXml.append("<Query>\r\n");  
1115 - cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");  
1116 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1117 - if (ObjectUtils.isEmpty(channelId)) {  
1118 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1119 - } else {  
1120 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1121 - }  
1122 - cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");  
1123 - cmdXml.append("</Query>\r\n");  
1124 -  
1125 -  
1126 -  
1127 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1128 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1129 - }  
1130 -  
1131 - /**  
1132 - * 查询设备预置位置  
1133 - *  
1134 - * @param device 视频设备  
1135 - */  
1136 - @Override  
1137 - public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1138 -  
1139 - StringBuffer cmdXml = new StringBuffer(200);  
1140 - String charset = device.getCharset();  
1141 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1142 - cmdXml.append("<Query>\r\n");  
1143 - cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");  
1144 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1145 - if (ObjectUtils.isEmpty(channelId)) {  
1146 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1147 - } else {  
1148 - cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1149 - }  
1150 - cmdXml.append("</Query>\r\n");  
1151 -  
1152 -  
1153 - Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1154 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1155 - }  
1156 -  
1157 - /**  
1158 - * 查询移动设备位置数据  
1159 - *  
1160 - * @param device 视频设备  
1161 - */  
1162 - @Override  
1163 - public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1164 -  
1165 - StringBuffer mobilePostitionXml = new StringBuffer(200);  
1166 - String charset = device.getCharset();  
1167 - mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1168 - mobilePostitionXml.append("<Query>\r\n");  
1169 - mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");  
1170 - mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1171 - mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1172 - mobilePostitionXml.append("<Interval>60</Interval>\r\n");  
1173 - mobilePostitionXml.append("</Query>\r\n");  
1174 -  
1175 -  
1176 -  
1177 - Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1178 -  
1179 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);  
1180 -  
1181 - }  
1182 -  
1183 - /**  
1184 - * 订阅、取消订阅移动位置  
1185 - *  
1186 - * @param device 视频设备  
1187 - * @return true = 命令发送成功  
1188 - */  
1189 - @Override  
1190 - public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1191 -  
1192 - StringBuffer subscribePostitionXml = new StringBuffer(200);  
1193 - String charset = device.getCharset();  
1194 - subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1195 - subscribePostitionXml.append("<Query>\r\n");  
1196 - subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");  
1197 - subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1198 - subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1199 - if (device.getSubscribeCycleForMobilePosition() > 0) {  
1200 - subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");  
1201 - }  
1202 - subscribePostitionXml.append("</Query>\r\n");  
1203 -  
1204 - CallIdHeader callIdHeader;  
1205 -  
1206 - if (requestOld != null) {  
1207 - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());  
1208 - } else {  
1209 - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());  
1210 - }  
1211 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));  
1212 -  
1213 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1214 - return request;  
1215 - }  
1216 -  
1217 - /**  
1218 - * 订阅、取消订阅报警信息  
1219 - *  
1220 - * @param device 视频设备  
1221 - * @param expires 订阅过期时间(0 = 取消订阅)  
1222 - * @param startPriority 报警起始级别(可选)  
1223 - * @param endPriority 报警终止级别(可选)  
1224 - * @param alarmMethod 报警方式条件(可选)  
1225 - * @param alarmType 报警类型  
1226 - * @param startTime 报警发生起始时间(可选)  
1227 - * @param endTime 报警发生终止时间(可选)  
1228 - * @return true = 命令发送成功  
1229 - */  
1230 - @Override  
1231 - public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException {  
1232 -  
1233 - StringBuffer cmdXml = new StringBuffer(200);  
1234 - String charset = device.getCharset();  
1235 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1236 - cmdXml.append("<Query>\r\n");  
1237 - cmdXml.append("<CmdType>Alarm</CmdType>\r\n");  
1238 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1239 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1240 - if (!ObjectUtils.isEmpty(startPriority)) {  
1241 - cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");  
1242 - }  
1243 - if (!ObjectUtils.isEmpty(endPriority)) {  
1244 - cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");  
1245 - }  
1246 - if (!ObjectUtils.isEmpty(alarmMethod)) {  
1247 - cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");  
1248 - }  
1249 - if (!ObjectUtils.isEmpty(startTime)) {  
1250 - cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");  
1251 - }  
1252 - if (!ObjectUtils.isEmpty(endTime)) {  
1253 - cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");  
1254 - }  
1255 - cmdXml.append("</Query>\r\n");  
1256 -  
1257 -  
1258 -  
1259 - Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1260 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);  
1261 -  
1262 - }  
1263 -  
1264 - @Override  
1265 - public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {  
1266 -  
1267 - StringBuffer cmdXml = new StringBuffer(200);  
1268 - String charset = device.getCharset();  
1269 - cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1270 - cmdXml.append("<Query>\r\n");  
1271 - cmdXml.append("<CmdType>Catalog</CmdType>\r\n");  
1272 - cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1273 - cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1274 - cmdXml.append("</Query>\r\n");  
1275 -  
1276 - CallIdHeader callIdHeader;  
1277 -  
1278 - if (requestOld != null) {  
1279 - callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());  
1280 - } else {  
1281 - callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());  
1282 - }  
1283 -  
1284 - // 有效时间默认为60秒以上  
1285 - SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog",  
1286 - callIdHeader);  
1287 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1288 - return request;  
1289 - }  
1290 -  
1291 - @Override  
1292 - public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException {  
1293 -  
1294 - StringBuffer dragXml = new StringBuffer(200);  
1295 - String charset = device.getCharset();  
1296 - dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");  
1297 - dragXml.append("<Control>\r\n");  
1298 - dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");  
1299 - dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1300 - if (ObjectUtils.isEmpty(channelId)) {  
1301 - dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");  
1302 - } else {  
1303 - dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");  
1304 - }  
1305 - dragXml.append(cmdString);  
1306 - dragXml.append("</Control>\r\n");  
1307 -  
1308 - Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1309 - logger.debug("拉框信令: " + request.toString());  
1310 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
1311 - }  
1312 -  
1313 -  
1314 -  
1315 -  
1316 -  
1317 - /**  
1318 - * 回放暂停  
1319 - */  
1320 - @Override  
1321 - public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {  
1322 - StringBuffer content = new StringBuffer(200);  
1323 - content.append("PAUSE RTSP/1.0\r\n");  
1324 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1325 - content.append("PauseTime: now\r\n");  
1326 -  
1327 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1328 - }  
1329 -  
1330 -  
1331 - /**  
1332 - * 回放恢复  
1333 - */  
1334 - @Override  
1335 - public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {  
1336 - StringBuffer content = new StringBuffer(200);  
1337 - content.append("PLAY RTSP/1.0\r\n");  
1338 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1339 - content.append("Range: npt=now-\r\n");  
1340 -  
1341 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1342 - }  
1343 -  
1344 - /**  
1345 - * 回放拖动播放  
1346 - */  
1347 - @Override  
1348 - public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException {  
1349 - StringBuffer content = new StringBuffer(200);  
1350 - content.append("PLAY RTSP/1.0\r\n");  
1351 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1352 - content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");  
1353 -  
1354 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1355 - }  
1356 -  
1357 - /**  
1358 - * 回放倍速播放  
1359 - */  
1360 - @Override  
1361 - public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException {  
1362 - StringBuffer content = new StringBuffer(200);  
1363 - content.append("PLAY RTSP/1.0\r\n");  
1364 - content.append("CSeq: " + getInfoCseq() + "\r\n");  
1365 - content.append("Scale: " + String.format("%.6f", speed) + "\r\n");  
1366 -  
1367 - playbackControlCmd(device, streamInfo, content.toString(), null, null);  
1368 - }  
1369 -  
1370 - private int getInfoCseq() {  
1371 - return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));  
1372 - }  
1373 -  
1374 - @Override  
1375 - public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {  
1376 -  
1377 - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream());  
1378 - if (ssrcTransaction == null) {  
1379 - logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());  
1380 - return;  
1381 - }  
1382 -  
1383 - SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo());  
1384 - if (request == null) {  
1385 - logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());  
1386 - return;  
1387 - }  
1388 -  
1389 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);  
1390 - }  
1391 -  
1392 - @Override  
1393 - public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException {  
1394 - if (device == null) {  
1395 - return;  
1396 - }  
1397 - logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),  
1398 - deviceAlarm.getLongitude(), deviceAlarm.getLatitude());  
1399 -  
1400 - String characterSet = device.getCharset();  
1401 - StringBuffer deviceStatusXml = new StringBuffer(600);  
1402 - deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");  
1403 - deviceStatusXml.append("<Notify>\r\n");  
1404 - deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");  
1405 - deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");  
1406 - deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");  
1407 - deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");  
1408 - deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");  
1409 - deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n");  
1410 - deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");  
1411 - deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");  
1412 - deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");  
1413 - deviceStatusXml.append("<info>\r\n");  
1414 - deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");  
1415 - deviceStatusXml.append("</info>\r\n");  
1416 - deviceStatusXml.append("</Notify>\r\n");  
1417 -  
1418 -  
1419 - Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));  
1420 - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);  
1421 -  
1422 -  
1423 - }  
1424 -} 1 +package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
  2 +
  3 +import com.genersoft.iot.vmp.common.InviteSessionType;
  4 +import com.genersoft.iot.vmp.common.StreamInfo;
  5 +import com.genersoft.iot.vmp.conf.SipConfig;
  6 +import com.genersoft.iot.vmp.conf.UserSetting;
  7 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  8 +import com.genersoft.iot.vmp.gb28181.SipLayer;
  9 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  10 +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
  11 +import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction;
  12 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
  13 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  14 +import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
  15 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.SIPRequestHeaderProvider;
  17 +import com.genersoft.iot.vmp.gb28181.utils.NumericUtil;
  18 +import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
  19 +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
  20 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory;
  21 +import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange;
  22 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  23 +import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam;
  24 +import com.genersoft.iot.vmp.service.IMediaServerService;
  25 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  26 +import com.genersoft.iot.vmp.utils.DateUtil;
  27 +import gov.nist.javax.sip.message.SIPRequest;
  28 +import gov.nist.javax.sip.message.SIPResponse;
  29 +import org.slf4j.Logger;
  30 +import org.slf4j.LoggerFactory;
  31 +import org.springframework.beans.factory.annotation.Autowired;
  32 +import org.springframework.context.annotation.DependsOn;
  33 +import org.springframework.stereotype.Component;
  34 +import org.springframework.util.ObjectUtils;
  35 +
  36 +import javax.sip.InvalidArgumentException;
  37 +import javax.sip.ResponseEvent;
  38 +import javax.sip.SipException;
  39 +import javax.sip.SipFactory;
  40 +import javax.sip.header.CallIdHeader;
  41 +import javax.sip.message.Request;
  42 +import java.text.ParseException;
  43 +
  44 +/**
  45 + * @description:设备能力接口,用于定义设备的控制、查询能力
  46 + * @author: swwheihei
  47 + * @date: 2020年5月3日 下午9:22:48
  48 + */
  49 +@Component
  50 +@DependsOn("sipLayer")
  51 +public class SIPCommander implements ISIPCommander {
  52 +
  53 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
  54 +
  55 + @Autowired
  56 + private SipConfig sipConfig;
  57 +
  58 + @Autowired
  59 + private SipLayer sipLayer;
  60 +
  61 + @Autowired
  62 + private SIPSender sipSender;
  63 +
  64 + @Autowired
  65 + private SIPRequestHeaderProvider headerProvider;
  66 +
  67 + @Autowired
  68 + private VideoStreamSessionManager streamSession;
  69 +
  70 + @Autowired
  71 + private UserSetting userSetting;
  72 +
  73 + @Autowired
  74 + private ZlmHttpHookSubscribe subscribe;
  75 +
  76 +
  77 +
  78 + @Autowired
  79 + private IMediaServerService mediaServerService;
  80 +
  81 +
  82 + /**
  83 + * 云台方向放控制,使用配置文件中的默认镜头移动速度
  84 + *
  85 + * @param device 控制设备
  86 + * @param channelId 预览通道
  87 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  88 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  89 + */
  90 + @Override
  91 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException {
  92 + ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0);
  93 + }
  94 +
  95 + /**
  96 + * 云台方向放控制
  97 + *
  98 + * @param device 控制设备
  99 + * @param channelId 预览通道
  100 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  101 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  102 + * @param moveSpeed 镜头移动速度
  103 + */
  104 + @Override
  105 + public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException {
  106 + ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0);
  107 + }
  108 +
  109 + /**
  110 + * 云台缩放控制,使用配置文件中的默认镜头缩放速度
  111 + *
  112 + * @param device 控制设备
  113 + * @param channelId 预览通道
  114 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  115 + */
  116 + @Override
  117 + public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException {
  118 + ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed());
  119 + }
  120 +
  121 + /**
  122 + * 云台缩放控制
  123 + *
  124 + * @param device 控制设备
  125 + * @param channelId 预览通道
  126 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  127 + * @param zoomSpeed 镜头缩放速度
  128 + */
  129 + @Override
  130 + public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException {
  131 + ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed);
  132 + }
  133 +
  134 + /**
  135 + * 云台指令码计算
  136 + *
  137 + * @param cmdCode 指令码
  138 + * @param parameter1 数据1
  139 + * @param parameter2 数据2
  140 + * @param combineCode2 组合码2
  141 + */
  142 + public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
  143 + StringBuilder builder = new StringBuilder("A50F01");
  144 + String strTmp;
  145 + strTmp = String.format("%02X", cmdCode);
  146 + builder.append(strTmp, 0, 2);
  147 + strTmp = String.format("%02X", parameter1);
  148 + builder.append(strTmp, 0, 2);
  149 + strTmp = String.format("%02X", parameter2);
  150 + builder.append(strTmp, 0, 2);
  151 + //优化zoom变倍速率
  152 + if ((combineCode2 > 0) && (combineCode2 <16))
  153 + {
  154 + combineCode2 = 16;
  155 + }
  156 + strTmp = String.format("%X", combineCode2);
  157 + builder.append(strTmp, 0, 1).append("0");
  158 + //计算校验码
  159 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
  160 + strTmp = String.format("%02X", checkCode);
  161 + builder.append(strTmp, 0, 2);
  162 + return builder.toString();
  163 + }
  164 +
  165 + /**
  166 + * 云台控制,支持方向与缩放控制
  167 + *
  168 + * @param device 控制设备
  169 + * @param channelId 预览通道
  170 + * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移
  171 + * @param upDown 镜头上移下移 0:停止 1:上移 2:下移
  172 + * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大
  173 + * @param moveSpeed 镜头移动速度
  174 + * @param zoomSpeed 镜头缩放速度
  175 + */
  176 + @Override
  177 + public void ptzCmd(Device device, String channelId, int leftRight, int upDown, int inOut, int moveSpeed,
  178 + int zoomSpeed) throws InvalidArgumentException, SipException, ParseException {
  179 + String cmdStr = SipUtils.cmdString(leftRight, upDown, inOut, moveSpeed, zoomSpeed);
  180 + StringBuilder ptzXml = new StringBuilder(200);
  181 + String charset = device.getCharset();
  182 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  183 + ptzXml.append("<Control>\r\n");
  184 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  185 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  186 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  187 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  188 + ptzXml.append("<Info>\r\n");
  189 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  190 + ptzXml.append("</Info>\r\n");
  191 + ptzXml.append("</Control>\r\n");
  192 +
  193 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  194 +
  195 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  196 + }
  197 +
  198 + /**
  199 + * 前端控制,包括PTZ指令、FI指令、预置位指令、巡航指令、扫描指令和辅助开关指令
  200 + *
  201 + * @param device 控制设备
  202 + * @param channelId 预览通道
  203 + * @param cmdCode 指令码
  204 + * @param parameter1 数据1
  205 + * @param parameter2 数据2
  206 + * @param combineCode2 组合码2
  207 + */
  208 + @Override
  209 + public void frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) throws SipException, InvalidArgumentException, ParseException {
  210 +
  211 + String cmdStr = frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
  212 + StringBuffer ptzXml = new StringBuffer(200);
  213 + String charset = device.getCharset();
  214 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  215 + ptzXml.append("<Control>\r\n");
  216 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  217 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  218 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  219 + ptzXml.append("<PTZCmd>" + cmdStr + "</PTZCmd>\r\n");
  220 + ptzXml.append("<Info>\r\n");
  221 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  222 + ptzXml.append("</Info>\r\n");
  223 + ptzXml.append("</Control>\r\n");
  224 +
  225 +
  226 +
  227 +
  228 + SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  229 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  230 +
  231 + }
  232 +
  233 + /**
  234 + * 前端控制指令(用于转发上级指令)
  235 + *
  236 + * @param device 控制设备
  237 + * @param channelId 预览通道
  238 + * @param cmdString 前端控制指令串
  239 + */
  240 + @Override
  241 + public void fronEndCmd(Device device, String channelId, String cmdString, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  242 +
  243 + StringBuffer ptzXml = new StringBuffer(200);
  244 + String charset = device.getCharset();
  245 + ptzXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  246 + ptzXml.append("<Control>\r\n");
  247 + ptzXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  248 + ptzXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  249 + ptzXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  250 + ptzXml.append("<PTZCmd>" + cmdString + "</PTZCmd>\r\n");
  251 + ptzXml.append("<Info>\r\n");
  252 + ptzXml.append("<ControlPriority>5</ControlPriority>\r\n");
  253 + ptzXml.append("</Info>\r\n");
  254 + ptzXml.append("</Control>\r\n");
  255 +
  256 +
  257 + Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  258 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request, errorEvent, okEvent);
  259 +
  260 + }
  261 +
  262 + /**
  263 + * 请求预览视频流
  264 + *
  265 + * @param device 视频设备
  266 + * @param channelId 预览通道
  267 + * @param event hook订阅
  268 + * @param errorEvent sip错误订阅
  269 + */
  270 + @Override
  271 + public void playStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  272 + ZlmHttpHookSubscribe.Event event, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  273 + String stream = ssrcInfo.getStream();
  274 +
  275 + if (device == null) {
  276 + return;
  277 + }
  278 +
  279 + logger.info("{} 分配的ZLM为: {} [{}:{}]", stream, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  280 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", stream, true, "rtsp", mediaServerItem.getId());
  281 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
  282 + if (event != null) {
  283 + event.response(mediaServerItemInUse, hookParam);
  284 + subscribe.removeSubscribe(hookSubscribe);
  285 + }
  286 + });
  287 + String sdpIp;
  288 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  289 + sdpIp = device.getSdpIp();
  290 + }else {
  291 + sdpIp = mediaServerItem.getSdpIp();
  292 + }
  293 + StringBuffer content = new StringBuffer(200);
  294 + content.append("v=0\r\n");
  295 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  296 + content.append("s=Play\r\n");
  297 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  298 + content.append("t=0 0\r\n");
  299 +
  300 + if (userSetting.isSeniorSdp()) {
  301 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  302 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  303 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  304 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  305 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  306 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  307 + }
  308 + content.append("a=recvonly\r\n");
  309 + content.append("a=rtpmap:96 PS/90000\r\n");
  310 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  311 + content.append("a=rtpmap:126 H264/90000\r\n");
  312 + content.append("a=rtpmap:125 H264S/90000\r\n");
  313 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  314 + content.append("a=rtpmap:99 H265/90000\r\n");
  315 + content.append("a=rtpmap:98 H264/90000\r\n");
  316 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  317 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  318 + content.append("a=setup:passive\r\n");
  319 + content.append("a=connection:new\r\n");
  320 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  321 + content.append("a=setup:active\r\n");
  322 + content.append("a=connection:new\r\n");
  323 + }
  324 + } else {
  325 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) {
  326 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  327 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) {
  328 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  329 + } else if ("UDP".equalsIgnoreCase(device.getStreamMode())) {
  330 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  331 + }
  332 + content.append("a=recvonly\r\n");
  333 + content.append("a=rtpmap:96 PS/90000\r\n");
  334 + content.append("a=rtpmap:98 H264/90000\r\n");
  335 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  336 + content.append("a=rtpmap:99 H265/90000\r\n");
  337 + if ("TCP-PASSIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp被动模式
  338 + content.append("a=setup:passive\r\n");
  339 + content.append("a=connection:new\r\n");
  340 + } else if ("TCP-ACTIVE".equalsIgnoreCase(device.getStreamMode())) { // tcp主动模式
  341 + content.append("a=setup:active\r\n");
  342 + content.append("a=connection:new\r\n");
  343 + }
  344 + }
  345 +
  346 + if( device.isSwitchPrimarySubStream() ){
  347 + if("TP-LINK".equals(device.getManufacturer())){
  348 + if (device.isSwitchPrimarySubStream()){
  349 + content.append("a=streamMode:sub\r\n");
  350 + }else {
  351 + content.append("a=streamMode:main\r\n");
  352 + }
  353 + }else {
  354 + if (device.isSwitchPrimarySubStream()){
  355 + content.append("a=streamprofile:1\r\n");
  356 + }else {
  357 + content.append("a=streamprofile:0\r\n");
  358 + }
  359 + }
  360 + }
  361 +
  362 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  363 + // f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
  364 +// content.append("f=v/2/5/25/1/4000a/1/8/1" + "\r\n"); // 未发现支持此特性的设备
  365 +
  366 +
  367 +
  368 + Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  369 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> {
  370 + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream());
  371 + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc());
  372 + errorEvent.response(e);
  373 + }), e -> {
  374 + ResponseEvent responseEvent = (ResponseEvent) e.event;
  375 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  376 + streamSession.put(device.getDeviceId(), channelId, "play", stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response,
  377 + InviteSessionType.PLAY);
  378 + okEvent.response(e);
  379 + });
  380 + }
  381 +
  382 + /**
  383 + * 请求回放视频流
  384 + *
  385 + * @param device 视频设备
  386 + * @param channelId 预览通道
  387 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  388 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  389 + */
  390 + @Override
  391 + public void playbackStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  392 + String startTime, String endTime, ZlmHttpHookSubscribe.Event hookEvent,
  393 + SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  394 +
  395 +
  396 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  397 + String sdpIp;
  398 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  399 + sdpIp = device.getSdpIp();
  400 + }else {
  401 + sdpIp = mediaServerItem.getSdpIp();
  402 + }
  403 + StringBuffer content = new StringBuffer(200);
  404 + content.append("v=0\r\n");
  405 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  406 + content.append("s=Playback\r\n");
  407 + content.append("u=" + channelId + ":0\r\n");
  408 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  409 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  410 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  411 +
  412 + String streamMode = device.getStreamMode();
  413 +
  414 + if (userSetting.isSeniorSdp()) {
  415 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  416 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  417 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  418 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  419 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  420 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  421 + }
  422 + content.append("a=recvonly\r\n");
  423 + content.append("a=rtpmap:96 PS/90000\r\n");
  424 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  425 + content.append("a=rtpmap:126 H264/90000\r\n");
  426 + content.append("a=rtpmap:125 H264S/90000\r\n");
  427 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  428 + content.append("a=rtpmap:99 H265/90000\r\n");
  429 + content.append("a=rtpmap:98 H264/90000\r\n");
  430 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  431 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) { // tcp被动模式
  432 + content.append("a=setup:passive\r\n");
  433 + content.append("a=connection:new\r\n");
  434 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) { // tcp主动模式
  435 + content.append("a=setup:active\r\n");
  436 + content.append("a=connection:new\r\n");
  437 + }
  438 + } else {
  439 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  440 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  441 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  442 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  443 + } else if ("UDP".equalsIgnoreCase(streamMode)) {
  444 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  445 + }
  446 + content.append("a=recvonly\r\n");
  447 + content.append("a=rtpmap:96 PS/90000\r\n");
  448 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  449 + content.append("a=rtpmap:98 H264/90000\r\n");
  450 + content.append("a=rtpmap:99 H265/90000\r\n");
  451 + if ("TCP-PASSIVE".equalsIgnoreCase(streamMode)) {
  452 + // tcp被动模式
  453 + content.append("a=setup:passive\r\n");
  454 + content.append("a=connection:new\r\n");
  455 + } else if ("TCP-ACTIVE".equalsIgnoreCase(streamMode)) {
  456 + // tcp主动模式
  457 + content.append("a=setup:active\r\n");
  458 + content.append("a=connection:new\r\n");
  459 + }
  460 + }
  461 +
  462 + //ssrc
  463 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");
  464 +
  465 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  466 + // 添加订阅
  467 + subscribe.addSubscribe(hookSubscribe, (MediaServerItem mediaServerItemInUse, HookParam hookParam) -> {
  468 + if (hookEvent != null) {
  469 + hookEvent.response(mediaServerItemInUse, hookParam);
  470 + }
  471 + subscribe.removeSubscribe(hookSubscribe);
  472 + });
  473 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()), ssrcInfo.getSsrc());
  474 +
  475 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
  476 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  477 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  478 + streamSession.put(device.getDeviceId(), channelId,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK);
  479 + okEvent.response(event);
  480 + });
  481 + }
  482 +
  483 + /**
  484 + * 请求历史媒体下载
  485 + *
  486 + * @param device 视频设备
  487 + * @param channelId 预览通道
  488 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  489 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  490 + * @param downloadSpeed 下载倍速参数
  491 + */
  492 + @Override
  493 + public void downloadStreamCmd(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, Device device, String channelId,
  494 + String startTime, String endTime, int downloadSpeed,
  495 + ZlmHttpHookSubscribe.Event hookEvent,
  496 + SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  497 +
  498 + logger.info("{} 分配的ZLM为: {} [{}:{}]", ssrcInfo.getStream(), mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort());
  499 + String sdpIp;
  500 + if (!ObjectUtils.isEmpty(device.getSdpIp())) {
  501 + sdpIp = device.getSdpIp();
  502 + }else {
  503 + sdpIp = mediaServerItem.getSdpIp();
  504 + }
  505 + StringBuffer content = new StringBuffer(200);
  506 + content.append("v=0\r\n");
  507 + content.append("o=" + channelId + " 0 0 IN IP4 " + sdpIp + "\r\n");
  508 + content.append("s=Download\r\n");
  509 + content.append("u=" + channelId + ":0\r\n");
  510 + content.append("c=IN IP4 " + sdpIp + "\r\n");
  511 + content.append("t=" + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime) + " "
  512 + + DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime) + "\r\n");
  513 +
  514 + String streamMode = device.getStreamMode().toUpperCase();
  515 +
  516 + if (userSetting.isSeniorSdp()) {
  517 + if ("TCP-PASSIVE".equals(streamMode)) {
  518 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  519 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  520 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 126 125 99 34 98 97\r\n");
  521 + } else if ("UDP".equals(streamMode)) {
  522 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 126 125 99 34 98 97\r\n");
  523 + }
  524 + content.append("a=recvonly\r\n");
  525 + content.append("a=rtpmap:96 PS/90000\r\n");
  526 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  527 + content.append("a=rtpmap:126 H264/90000\r\n");
  528 + content.append("a=rtpmap:125 H264S/90000\r\n");
  529 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  530 + content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
  531 + content.append("a=fmtp:99 profile-level-id=3\r\n");
  532 + content.append("a=rtpmap:98 H264/90000\r\n");
  533 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  534 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  535 + content.append("a=setup:passive\r\n");
  536 + content.append("a=connection:new\r\n");
  537 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  538 + content.append("a=setup:active\r\n");
  539 + content.append("a=connection:new\r\n");
  540 + }
  541 + } else {
  542 + if ("TCP-PASSIVE".equals(streamMode)) {
  543 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  544 + } else if ("TCP-ACTIVE".equals(streamMode)) {
  545 + content.append("m=video " + ssrcInfo.getPort() + " TCP/RTP/AVP 96 97 98 99\r\n");
  546 + } else if ("UDP".equals(streamMode)) {
  547 + content.append("m=video " + ssrcInfo.getPort() + " RTP/AVP 96 97 98 99\r\n");
  548 + }
  549 + content.append("a=recvonly\r\n");
  550 + content.append("a=rtpmap:96 PS/90000\r\n");
  551 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  552 + content.append("a=rtpmap:98 H264/90000\r\n");
  553 + content.append("a=rtpmap:99 H265/90000\r\n");
  554 + if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
  555 + content.append("a=setup:passive\r\n");
  556 + content.append("a=connection:new\r\n");
  557 + } else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  558 + content.append("a=setup:active\r\n");
  559 + content.append("a=connection:new\r\n");
  560 + }
  561 + }
  562 + content.append("a=downloadspeed:" + downloadSpeed + "\r\n");
  563 +
  564 + content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
  565 + logger.debug("此时请求下载信令的ssrc===>{}",ssrcInfo.getSsrc());
  566 + HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId());
  567 + // 添加订阅
  568 + CallIdHeader newCallIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), device.getTransport());
  569 + String callId= newCallIdHeader.getCallId();
  570 + subscribe.addSubscribe(hookSubscribe, (mediaServerItemInUse, hookParam) -> {
  571 + logger.debug("sipc 添加订阅===callId {}",callId);
  572 + hookEvent.response(mediaServerItemInUse, hookParam);
  573 + subscribe.removeSubscribe(hookSubscribe);
  574 + hookSubscribe.getContent().put("regist", false);
  575 + hookSubscribe.getContent().put("schema", "rtsp");
  576 + // 添加流注销的订阅,注销了后向设备发送bye
  577 + subscribe.addSubscribe(hookSubscribe,
  578 + (mediaServerItemForEnd, hookParam1) -> {
  579 + logger.info("[录像]下载结束, 发送BYE");
  580 + try {
  581 + streamByeCmd(device, channelId, ssrcInfo.getStream(), callId);
  582 + } catch (InvalidArgumentException | ParseException | SipException |
  583 + SsrcTransactionNotFoundException e) {
  584 + logger.error("[录像]下载结束, 发送BYE失败 {}", e.getMessage());
  585 + }
  586 + });
  587 + });
  588 +
  589 + Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,newCallIdHeader, ssrcInfo.getSsrc());
  590 +
  591 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, event -> {
  592 + ResponseEvent responseEvent = (ResponseEvent) event.event;
  593 + SIPResponse response = (SIPResponse) responseEvent.getResponse();
  594 + String contentString =new String(response.getRawContent());
  595 + String ssrc = SipUtils.getSsrcFromSdp(contentString);
  596 + streamSession.put(device.getDeviceId(), channelId, response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD);
  597 + okEvent.response(event);
  598 + });
  599 + }
  600 +
  601 + /**
  602 + * 视频流停止, 不使用回调
  603 + */
  604 + @Override
  605 + public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException {
  606 + streamByeCmd(device, channelId, stream, callId, null);
  607 + }
  608 +
  609 + /**
  610 + * 视频流停止
  611 + */
  612 + @Override
  613 + public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException {
  614 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, callId, stream);
  615 + if (ssrcTransaction == null) {
  616 + throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream);
  617 + }
  618 +
  619 + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc());
  620 + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream());
  621 + streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream());
  622 +
  623 + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo());
  624 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent);
  625 + }
  626 +
  627 + /**
  628 + * 语音广播
  629 + *
  630 + * @param device 视频设备
  631 + * @param channelId 预览通道
  632 + */
  633 + @Override
  634 + public void audioBroadcastCmd(Device device, String channelId) {
  635 + }
  636 +
  637 + /**
  638 + * 语音广播
  639 + *
  640 + * @param device 视频设备
  641 + */
  642 + @Override
  643 + public void audioBroadcastCmd(Device device) throws InvalidArgumentException, SipException, ParseException {
  644 +
  645 + StringBuffer broadcastXml = new StringBuffer(200);
  646 + String charset = device.getCharset();
  647 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  648 + broadcastXml.append("<Notify>\r\n");
  649 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  650 + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  651 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  652 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  653 + broadcastXml.append("</Notify>\r\n");
  654 +
  655 +
  656 +
  657 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  658 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  659 +
  660 + }
  661 +
  662 + @Override
  663 + public void audioBroadcastCmd(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  664 +
  665 + StringBuffer broadcastXml = new StringBuffer(200);
  666 + String charset = device.getCharset();
  667 + broadcastXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  668 + broadcastXml.append("<Notify>\r\n");
  669 + broadcastXml.append("<CmdType>Broadcast</CmdType>\r\n");
  670 + broadcastXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  671 + broadcastXml.append("<SourceID>" + sipConfig.getId() + "</SourceID>\r\n");
  672 + broadcastXml.append("<TargetID>" + device.getDeviceId() + "</TargetID>\r\n");
  673 + broadcastXml.append("</Notify>\r\n");
  674 +
  675 +
  676 +
  677 + Request request = headerProvider.createMessageRequest(device, broadcastXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  678 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  679 +
  680 + }
  681 +
  682 +
  683 + /**
  684 + * 音视频录像控制
  685 + *
  686 + * @param device 视频设备
  687 + * @param channelId 预览通道
  688 + * @param recordCmdStr 录像命令:Record / StopRecord
  689 + */
  690 + @Override
  691 + public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  692 + StringBuffer cmdXml = new StringBuffer(200);
  693 + String charset = device.getCharset();
  694 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  695 + cmdXml.append("<Control>\r\n");
  696 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  697 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  698 + if (ObjectUtils.isEmpty(channelId)) {
  699 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  700 + } else {
  701 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  702 + }
  703 + cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
  704 + cmdXml.append("</Control>\r\n");
  705 +
  706 +
  707 +
  708 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  709 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  710 + }
  711 +
  712 + /**
  713 + * 远程启动控制命令
  714 + *
  715 + * @param device 视频设备
  716 + */
  717 + @Override
  718 + public void teleBootCmd(Device device) throws InvalidArgumentException, SipException, ParseException {
  719 +
  720 + StringBuffer cmdXml = new StringBuffer(200);
  721 + String charset = device.getCharset();
  722 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  723 + cmdXml.append("<Control>\r\n");
  724 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  725 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  726 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  727 + cmdXml.append("<TeleBoot>Boot</TeleBoot>\r\n");
  728 + cmdXml.append("</Control>\r\n");
  729 +
  730 +
  731 +
  732 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  733 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  734 + }
  735 +
  736 + /**
  737 + * 报警布防/撤防命令
  738 + *
  739 + * @param device 视频设备
  740 + * @param guardCmdStr "SetGuard"/"ResetGuard"
  741 + */
  742 + @Override
  743 + public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  744 +
  745 + StringBuffer cmdXml = new StringBuffer(200);
  746 + String charset = device.getCharset();
  747 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  748 + cmdXml.append("<Control>\r\n");
  749 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  750 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  751 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  752 + cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
  753 + cmdXml.append("</Control>\r\n");
  754 +
  755 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  756 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  757 + }
  758 +
  759 + /**
  760 + * 报警复位命令
  761 + *
  762 + * @param device 视频设备
  763 + */
  764 + @Override
  765 + public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  766 +
  767 + StringBuffer cmdXml = new StringBuffer(200);
  768 + String charset = device.getCharset();
  769 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  770 + cmdXml.append("<Control>\r\n");
  771 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  772 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  773 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  774 + cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
  775 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  776 + cmdXml.append("<Info>\r\n");
  777 + }
  778 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  779 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  780 + }
  781 + if (!ObjectUtils.isEmpty(alarmType)) {
  782 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  783 + }
  784 + if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
  785 + cmdXml.append("</Info>\r\n");
  786 + }
  787 + cmdXml.append("</Control>\r\n");
  788 +
  789 +
  790 +
  791 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  792 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  793 + }
  794 +
  795 + /**
  796 + * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧
  797 + *
  798 + * @param device 视频设备
  799 + * @param channelId 预览通道
  800 + */
  801 + @Override
  802 + public void iFrameCmd(Device device, String channelId) throws InvalidArgumentException, SipException, ParseException {
  803 +
  804 + StringBuffer cmdXml = new StringBuffer(200);
  805 + String charset = device.getCharset();
  806 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  807 + cmdXml.append("<Control>\r\n");
  808 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  809 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  810 + if (ObjectUtils.isEmpty(channelId)) {
  811 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  812 + } else {
  813 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  814 + }
  815 + cmdXml.append("<IFameCmd>Send</IFameCmd>\r\n");
  816 + cmdXml.append("</Control>\r\n");
  817 +
  818 +
  819 +
  820 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  821 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  822 + }
  823 +
  824 + /**
  825 + * 看守位控制命令
  826 + *
  827 + * @param device 视频设备
  828 + * @param channelId 通道id,非通道则是设备本身
  829 + * @param enabled 看守位使能:1 = 开启,0 = 关闭
  830 + * @param resetTime 自动归位时间间隔,开启看守位时使用,单位:秒(s)
  831 + * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255
  832 + */
  833 + @Override
  834 + public void homePositionCmd(Device device, String channelId, String enabled, String resetTime, String presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException {
  835 +
  836 + StringBuffer cmdXml = new StringBuffer(200);
  837 + String charset = device.getCharset();
  838 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  839 + cmdXml.append("<Control>\r\n");
  840 + cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  841 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  842 + if (ObjectUtils.isEmpty(channelId)) {
  843 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  844 + } else {
  845 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  846 + }
  847 + cmdXml.append("<HomePosition>\r\n");
  848 + if (NumericUtil.isInteger(enabled) && (!enabled.equals("0"))) {
  849 + cmdXml.append("<Enabled>1</Enabled>\r\n");
  850 + if (NumericUtil.isInteger(resetTime)) {
  851 + cmdXml.append("<ResetTime>" + resetTime + "</ResetTime>\r\n");
  852 + } else {
  853 + cmdXml.append("<ResetTime>0</ResetTime>\r\n");
  854 + }
  855 + if (NumericUtil.isInteger(presetIndex)) {
  856 + cmdXml.append("<PresetIndex>" + presetIndex + "</PresetIndex>\r\n");
  857 + } else {
  858 + cmdXml.append("<PresetIndex>0</PresetIndex>\r\n");
  859 + }
  860 + } else {
  861 + cmdXml.append("<Enabled>0</Enabled>\r\n");
  862 + }
  863 + cmdXml.append("</HomePosition>\r\n");
  864 + cmdXml.append("</Control>\r\n");
  865 +
  866 +
  867 +
  868 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  869 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent);
  870 + }
  871 +
  872 + /**
  873 + * 设备配置命令
  874 + *
  875 + * @param device 视频设备
  876 + */
  877 + @Override
  878 + public void deviceConfigCmd(Device device) {
  879 + // TODO Auto-generated method stub
  880 + }
  881 +
  882 + /**
  883 + * 设备配置命令:basicParam
  884 + *
  885 + * @param device 视频设备
  886 + * @param channelId 通道编码(可选)
  887 + * @param name 设备/通道名称(可选)
  888 + * @param expiration 注册过期时间(可选)
  889 + * @param heartBeatInterval 心跳间隔时间(可选)
  890 + * @param heartBeatCount 心跳超时次数(可选)
  891 + */
  892 + @Override
  893 + public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration,
  894 + String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  895 +
  896 + StringBuffer cmdXml = new StringBuffer(200);
  897 + String charset = device.getCharset();
  898 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  899 + cmdXml.append("<Control>\r\n");
  900 + cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
  901 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  902 + if (ObjectUtils.isEmpty(channelId)) {
  903 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  904 + } else {
  905 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  906 + }
  907 + cmdXml.append("<BasicParam>\r\n");
  908 + if (!ObjectUtils.isEmpty(name)) {
  909 + cmdXml.append("<Name>" + name + "</Name>\r\n");
  910 + }
  911 + if (NumericUtil.isInteger(expiration)) {
  912 + if (Integer.valueOf(expiration) > 0) {
  913 + cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
  914 + }
  915 + }
  916 + if (NumericUtil.isInteger(heartBeatInterval)) {
  917 + if (Integer.valueOf(heartBeatInterval) > 0) {
  918 + cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
  919 + }
  920 + }
  921 + if (NumericUtil.isInteger(heartBeatCount)) {
  922 + if (Integer.valueOf(heartBeatCount) > 0) {
  923 + cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
  924 + }
  925 + }
  926 + cmdXml.append("</BasicParam>\r\n");
  927 + cmdXml.append("</Control>\r\n");
  928 +
  929 +
  930 +
  931 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  932 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  933 + }
  934 +
  935 + /**
  936 + * 查询设备状态
  937 + *
  938 + * @param device 视频设备
  939 + */
  940 + @Override
  941 + public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  942 +
  943 + String charset = device.getCharset();
  944 + StringBuffer catalogXml = new StringBuffer(200);
  945 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  946 + catalogXml.append("<Query>\r\n");
  947 + catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
  948 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  949 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  950 + catalogXml.append("</Query>\r\n");
  951 +
  952 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  953 +
  954 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  955 + }
  956 +
  957 + /**
  958 + * 查询设备信息
  959 + *
  960 + * @param device 视频设备
  961 + */
  962 + @Override
  963 + public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException {
  964 +
  965 + StringBuffer catalogXml = new StringBuffer(200);
  966 + String charset = device.getCharset();
  967 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  968 + catalogXml.append("<Query>\r\n");
  969 + catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
  970 + catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  971 + catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  972 + catalogXml.append("</Query>\r\n");
  973 +
  974 +
  975 +
  976 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  977 +
  978 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  979 +
  980 + }
  981 +
  982 + /**
  983 + * 查询目录列表
  984 + *
  985 + * @param device 视频设备
  986 + */
  987 + @Override
  988 + public void catalogQuery(Device device, int sn, SipSubscribe.Event errorEvent) throws SipException, InvalidArgumentException, ParseException {
  989 +
  990 + StringBuffer catalogXml = new StringBuffer(200);
  991 + String charset = device.getCharset();
  992 + catalogXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  993 + catalogXml.append("<Query>\r\n");
  994 + catalogXml.append(" <CmdType>Catalog</CmdType>\r\n");
  995 + catalogXml.append(" <SN>" + sn + "</SN>\r\n");
  996 + catalogXml.append(" <DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  997 + catalogXml.append("</Query>\r\n");
  998 +
  999 +
  1000 +
  1001 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1002 +
  1003 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1004 + }
  1005 +
  1006 + /**
  1007 + * 查询录像信息
  1008 + *
  1009 + * @param device 视频设备
  1010 + * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
  1011 + * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
  1012 + */
  1013 + @Override
  1014 + public void recordInfoQuery(Device device, String channelId, String startTime, String endTime, int sn, Integer secrecy, String type, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1015 + if (secrecy == null) {
  1016 + secrecy = 0;
  1017 + }
  1018 + if (type == null) {
  1019 + type = "all";
  1020 + }
  1021 +
  1022 + StringBuffer recordInfoXml = new StringBuffer(200);
  1023 + String charset = device.getCharset();
  1024 + recordInfoXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1025 + recordInfoXml.append("<Query>\r\n");
  1026 + recordInfoXml.append("<CmdType>RecordInfo</CmdType>\r\n");
  1027 + recordInfoXml.append("<SN>" + sn + "</SN>\r\n");
  1028 + recordInfoXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1029 + if (startTime != null) {
  1030 + recordInfoXml.append("<StartTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime) + "</StartTime>\r\n");
  1031 + }
  1032 + if (endTime != null) {
  1033 + recordInfoXml.append("<EndTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime) + "</EndTime>\r\n");
  1034 + }
  1035 + if (secrecy != null) {
  1036 + recordInfoXml.append("<Secrecy> " + secrecy + " </Secrecy>\r\n");
  1037 + }
  1038 + if (type != null) {
  1039 + // 大华NVR要求必须增加一个值为all的文本元素节点Type
  1040 + recordInfoXml.append("<Type>" + type + "</Type>\r\n");
  1041 + }
  1042 + recordInfoXml.append("</Query>\r\n");
  1043 +
  1044 +
  1045 +
  1046 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(),
  1047 + SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1048 +
  1049 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1050 + }
  1051 +
  1052 + /**
  1053 + * 查询报警信息
  1054 + *
  1055 + * @param device 视频设备
  1056 + * @param startPriority 报警起始级别(可选)
  1057 + * @param endPriority 报警终止级别(可选)
  1058 + * @param alarmMethod 报警方式条件(可选)
  1059 + * @param alarmType 报警类型
  1060 + * @param startTime 报警发生起始时间(可选)
  1061 + * @param endTime 报警发生终止时间(可选)
  1062 + * @return true = 命令发送成功
  1063 + */
  1064 + @Override
  1065 + public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType,
  1066 + String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1067 +
  1068 + StringBuffer cmdXml = new StringBuffer(200);
  1069 + String charset = device.getCharset();
  1070 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1071 + cmdXml.append("<Query>\r\n");
  1072 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1073 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1074 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1075 + if (!ObjectUtils.isEmpty(startPriority)) {
  1076 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1077 + }
  1078 + if (!ObjectUtils.isEmpty(endPriority)) {
  1079 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1080 + }
  1081 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1082 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1083 + }
  1084 + if (!ObjectUtils.isEmpty(alarmType)) {
  1085 + cmdXml.append("<AlarmType>" + alarmType + "</AlarmType>\r\n");
  1086 + }
  1087 + if (!ObjectUtils.isEmpty(startTime)) {
  1088 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1089 + }
  1090 + if (!ObjectUtils.isEmpty(endTime)) {
  1091 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1092 + }
  1093 + cmdXml.append("</Query>\r\n");
  1094 +
  1095 +
  1096 +
  1097 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1098 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1099 + }
  1100 +
  1101 + /**
  1102 + * 查询设备配置
  1103 + *
  1104 + * @param device 视频设备
  1105 + * @param channelId 通道编码(可选)
  1106 + * @param configType 配置类型:
  1107 + */
  1108 + @Override
  1109 + public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1110 +
  1111 + StringBuffer cmdXml = new StringBuffer(200);
  1112 + String charset = device.getCharset();
  1113 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1114 + cmdXml.append("<Query>\r\n");
  1115 + cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
  1116 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1117 + if (ObjectUtils.isEmpty(channelId)) {
  1118 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1119 + } else {
  1120 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1121 + }
  1122 + cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
  1123 + cmdXml.append("</Query>\r\n");
  1124 +
  1125 +
  1126 +
  1127 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1128 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1129 + }
  1130 +
  1131 + /**
  1132 + * 查询设备预置位置
  1133 + *
  1134 + * @param device 视频设备
  1135 + */
  1136 + @Override
  1137 + public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1138 +
  1139 + StringBuffer cmdXml = new StringBuffer(200);
  1140 + String charset = device.getCharset();
  1141 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1142 + cmdXml.append("<Query>\r\n");
  1143 + cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
  1144 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1145 + if (ObjectUtils.isEmpty(channelId)) {
  1146 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1147 + } else {
  1148 + cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1149 + }
  1150 + cmdXml.append("</Query>\r\n");
  1151 +
  1152 +
  1153 + Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1154 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1155 + }
  1156 +
  1157 + /**
  1158 + * 查询移动设备位置数据
  1159 + *
  1160 + * @param device 视频设备
  1161 + */
  1162 + @Override
  1163 + public void mobilePostitionQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1164 +
  1165 + StringBuffer mobilePostitionXml = new StringBuffer(200);
  1166 + String charset = device.getCharset();
  1167 + mobilePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1168 + mobilePostitionXml.append("<Query>\r\n");
  1169 + mobilePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1170 + mobilePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1171 + mobilePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1172 + mobilePostitionXml.append("<Interval>60</Interval>\r\n");
  1173 + mobilePostitionXml.append("</Query>\r\n");
  1174 +
  1175 +
  1176 +
  1177 + Request request = headerProvider.createMessageRequest(device, mobilePostitionXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1178 +
  1179 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent);
  1180 +
  1181 + }
  1182 +
  1183 + /**
  1184 + * 订阅、取消订阅移动位置
  1185 + *
  1186 + * @param device 视频设备
  1187 + * @return true = 命令发送成功
  1188 + */
  1189 + @Override
  1190 + public SIPRequest mobilePositionSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1191 +
  1192 + StringBuffer subscribePostitionXml = new StringBuffer(200);
  1193 + String charset = device.getCharset();
  1194 + subscribePostitionXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1195 + subscribePostitionXml.append("<Query>\r\n");
  1196 + subscribePostitionXml.append("<CmdType>MobilePosition</CmdType>\r\n");
  1197 + subscribePostitionXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1198 + subscribePostitionXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1199 + if (device.getSubscribeCycleForMobilePosition() > 0) {
  1200 + subscribePostitionXml.append("<Interval>" + device.getMobilePositionSubmissionInterval() + "</Interval>\r\n");
  1201 + }
  1202 + subscribePostitionXml.append("</Query>\r\n");
  1203 +
  1204 + CallIdHeader callIdHeader;
  1205 +
  1206 + if (requestOld != null) {
  1207 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1208 + } else {
  1209 + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
  1210 + }
  1211 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, subscribePostitionXml.toString(), requestOld, device.getSubscribeCycleForMobilePosition(), "presence",callIdHeader); //Position;id=" + tm.substring(tm.length() - 4));
  1212 +
  1213 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1214 + return request;
  1215 + }
  1216 +
  1217 + /**
  1218 + * 订阅、取消订阅报警信息
  1219 + *
  1220 + * @param device 视频设备
  1221 + * @param expires 订阅过期时间(0 = 取消订阅)
  1222 + * @param startPriority 报警起始级别(可选)
  1223 + * @param endPriority 报警终止级别(可选)
  1224 + * @param alarmMethod 报警方式条件(可选)
  1225 + * @param alarmType 报警类型
  1226 + * @param startTime 报警发生起始时间(可选)
  1227 + * @param endTime 报警发生终止时间(可选)
  1228 + * @return true = 命令发送成功
  1229 + */
  1230 + @Override
  1231 + public void alarmSubscribe(Device device, int expires, String startPriority, String endPriority, String alarmMethod, String startTime, String endTime) throws InvalidArgumentException, SipException, ParseException {
  1232 +
  1233 + StringBuffer cmdXml = new StringBuffer(200);
  1234 + String charset = device.getCharset();
  1235 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1236 + cmdXml.append("<Query>\r\n");
  1237 + cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
  1238 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1239 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1240 + if (!ObjectUtils.isEmpty(startPriority)) {
  1241 + cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
  1242 + }
  1243 + if (!ObjectUtils.isEmpty(endPriority)) {
  1244 + cmdXml.append("<EndAlarmPriority>" + endPriority + "</EndAlarmPriority>\r\n");
  1245 + }
  1246 + if (!ObjectUtils.isEmpty(alarmMethod)) {
  1247 + cmdXml.append("<AlarmMethod>" + alarmMethod + "</AlarmMethod>\r\n");
  1248 + }
  1249 + if (!ObjectUtils.isEmpty(startTime)) {
  1250 + cmdXml.append("<StartAlarmTime>" + startTime + "</StartAlarmTime>\r\n");
  1251 + }
  1252 + if (!ObjectUtils.isEmpty(endTime)) {
  1253 + cmdXml.append("<EndAlarmTime>" + endTime + "</EndAlarmTime>\r\n");
  1254 + }
  1255 + cmdXml.append("</Query>\r\n");
  1256 +
  1257 +
  1258 +
  1259 + Request request = headerProvider.createSubscribeRequest(device, cmdXml.toString(), null, expires, "presence",sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1260 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request);
  1261 +
  1262 + }
  1263 +
  1264 + @Override
  1265 + public SIPRequest catalogSubscribe(Device device, SIPRequest requestOld, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException {
  1266 +
  1267 + StringBuffer cmdXml = new StringBuffer(200);
  1268 + String charset = device.getCharset();
  1269 + cmdXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1270 + cmdXml.append("<Query>\r\n");
  1271 + cmdXml.append("<CmdType>Catalog</CmdType>\r\n");
  1272 + cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1273 + cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1274 + cmdXml.append("</Query>\r\n");
  1275 +
  1276 + CallIdHeader callIdHeader;
  1277 +
  1278 + if (requestOld != null) {
  1279 + callIdHeader = SipFactory.getInstance().createHeaderFactory().createCallIdHeader(requestOld.getCallIdHeader().getCallId());
  1280 + } else {
  1281 + callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport());
  1282 + }
  1283 +
  1284 + // 有效时间默认为60秒以上
  1285 + SIPRequest request = (SIPRequest) headerProvider.createSubscribeRequest(device, cmdXml.toString(), requestOld, device.getSubscribeCycleForCatalog(), "Catalog",
  1286 + callIdHeader);
  1287 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1288 + return request;
  1289 + }
  1290 +
  1291 + @Override
  1292 + public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException {
  1293 +
  1294 + StringBuffer dragXml = new StringBuffer(200);
  1295 + String charset = device.getCharset();
  1296 + dragXml.append("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
  1297 + dragXml.append("<Control>\r\n");
  1298 + dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
  1299 + dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1300 + if (ObjectUtils.isEmpty(channelId)) {
  1301 + dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
  1302 + } else {
  1303 + dragXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
  1304 + }
  1305 + dragXml.append(cmdString);
  1306 + dragXml.append("</Control>\r\n");
  1307 +
  1308 + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1309 + logger.debug("拉框信令: " + request.toString());
  1310 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  1311 + }
  1312 +
  1313 +
  1314 +
  1315 +
  1316 +
  1317 + /**
  1318 + * 回放暂停
  1319 + */
  1320 + @Override
  1321 + public void playPauseCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1322 + StringBuffer content = new StringBuffer(200);
  1323 + content.append("PAUSE RTSP/1.0\r\n");
  1324 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1325 + content.append("PauseTime: now\r\n");
  1326 +
  1327 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1328 + }
  1329 +
  1330 +
  1331 + /**
  1332 + * 回放恢复
  1333 + */
  1334 + @Override
  1335 + public void playResumeCmd(Device device, StreamInfo streamInfo) throws InvalidArgumentException, ParseException, SipException {
  1336 + StringBuffer content = new StringBuffer(200);
  1337 + content.append("PLAY RTSP/1.0\r\n");
  1338 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1339 + content.append("Range: npt=now-\r\n");
  1340 +
  1341 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1342 + }
  1343 +
  1344 + /**
  1345 + * 回放拖动播放
  1346 + */
  1347 + @Override
  1348 + public void playSeekCmd(Device device, StreamInfo streamInfo, long seekTime) throws InvalidArgumentException, ParseException, SipException {
  1349 + StringBuffer content = new StringBuffer(200);
  1350 + content.append("PLAY RTSP/1.0\r\n");
  1351 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1352 + content.append("Range: npt=" + Math.abs(seekTime) + "-\r\n");
  1353 +
  1354 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1355 + }
  1356 +
  1357 + /**
  1358 + * 回放倍速播放
  1359 + */
  1360 + @Override
  1361 + public void playSpeedCmd(Device device, StreamInfo streamInfo, Double speed) throws InvalidArgumentException, ParseException, SipException {
  1362 + StringBuffer content = new StringBuffer(200);
  1363 + content.append("PLAY RTSP/1.0\r\n");
  1364 + content.append("CSeq: " + getInfoCseq() + "\r\n");
  1365 + content.append("Scale: " + String.format("%.6f", speed) + "\r\n");
  1366 +
  1367 + playbackControlCmd(device, streamInfo, content.toString(), null, null);
  1368 + }
  1369 +
  1370 + private int getInfoCseq() {
  1371 + return (int) ((Math.random() * 9 + 1) * Math.pow(10, 8));
  1372 + }
  1373 +
  1374 + @Override
  1375 + public void playbackControlCmd(Device device, StreamInfo streamInfo, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException {
  1376 +
  1377 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), streamInfo.getChannelId(), null, streamInfo.getStream());
  1378 + if (ssrcTransaction == null) {
  1379 + logger.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1380 + return;
  1381 + }
  1382 +
  1383 + SIPRequest request = headerProvider.createInfoRequest(device, streamInfo.getChannelId(), content.toString(), ssrcTransaction.getSipTransactionInfo());
  1384 + if (request == null) {
  1385 + logger.info("[回放控制]构建Request信息失败,设备:{}, 流ID: {}", device.getDeviceId(), streamInfo.getStream());
  1386 + return;
  1387 + }
  1388 +
  1389 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent, okEvent);
  1390 + }
  1391 +
  1392 + @Override
  1393 + public void sendAlarmMessage(Device device, DeviceAlarm deviceAlarm) throws InvalidArgumentException, SipException, ParseException {
  1394 + if (device == null) {
  1395 + return;
  1396 + }
  1397 + logger.info("[发送报警通知]设备: {}/{}->{},{}", device.getDeviceId(), deviceAlarm.getChannelId(),
  1398 + deviceAlarm.getLongitude(), deviceAlarm.getLatitude());
  1399 +
  1400 + String characterSet = device.getCharset();
  1401 + StringBuffer deviceStatusXml = new StringBuffer(600);
  1402 + deviceStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n");
  1403 + deviceStatusXml.append("<Notify>\r\n");
  1404 + deviceStatusXml.append("<CmdType>Alarm</CmdType>\r\n");
  1405 + deviceStatusXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
  1406 + deviceStatusXml.append("<DeviceID>" + deviceAlarm.getChannelId() + "</DeviceID>\r\n");
  1407 + deviceStatusXml.append("<AlarmPriority>" + deviceAlarm.getAlarmPriority() + "</AlarmPriority>\r\n");
  1408 + deviceStatusXml.append("<AlarmMethod>" + deviceAlarm.getAlarmMethod() + "</AlarmMethod>\r\n");
  1409 + deviceStatusXml.append("<AlarmTime>" + DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(deviceAlarm.getAlarmTime()) + "</AlarmTime>\r\n");
  1410 + deviceStatusXml.append("<AlarmDescription>" + deviceAlarm.getAlarmDescription() + "</AlarmDescription>\r\n");
  1411 + deviceStatusXml.append("<Longitude>" + deviceAlarm.getLongitude() + "</Longitude>\r\n");
  1412 + deviceStatusXml.append("<Latitude>" + deviceAlarm.getLatitude() + "</Latitude>\r\n");
  1413 + deviceStatusXml.append("<info>\r\n");
  1414 + deviceStatusXml.append("<AlarmType>" + deviceAlarm.getAlarmType() + "</AlarmType>\r\n");
  1415 + deviceStatusXml.append("</info>\r\n");
  1416 + deviceStatusXml.append("</Notify>\r\n");
  1417 +
  1418 +
  1419 + Request request = headerProvider.createMessageRequest(device, deviceStatusXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()));
  1420 + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request);
  1421 +
  1422 +
  1423 + }
  1424 +}
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
@@ -18,10 +18,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; @@ -18,10 +18,7 @@ import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory;
18 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; 18 import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe;
19 import com.genersoft.iot.vmp.media.zlm.dto.*; 19 import com.genersoft.iot.vmp.media.zlm.dto.*;
20 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; 20 import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam;
21 -import com.genersoft.iot.vmp.service.IMediaServerService;  
22 -import com.genersoft.iot.vmp.service.IPlayService;  
23 -import com.genersoft.iot.vmp.service.IStreamProxyService;  
24 -import com.genersoft.iot.vmp.service.IStreamPushService; 21 +import com.genersoft.iot.vmp.service.*;
25 import com.genersoft.iot.vmp.service.bean.ErrorCallback; 22 import com.genersoft.iot.vmp.service.bean.ErrorCallback;
26 import com.genersoft.iot.vmp.service.bean.InviteErrorCode; 23 import com.genersoft.iot.vmp.service.bean.InviteErrorCode;
27 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel; 24 import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
@@ -80,6 +77,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -80,6 +77,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
80 private IRedisCatchStorage redisCatchStorage; 77 private IRedisCatchStorage redisCatchStorage;
81 78
82 @Autowired 79 @Autowired
  80 + private IInviteStreamService inviteStreamService;
  81 +
  82 + @Autowired
83 private SSRCFactory ssrcFactory; 83 private SSRCFactory ssrcFactory;
84 84
85 @Autowired 85 @Autowired
@@ -479,13 +479,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -479,13 +479,13 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
479 errorEvent.run(code, msg, data); 479 errorEvent.run(code, msg, data);
480 } 480 }
481 }); 481 });
482 - }else if ("Download".equalsIgnoreCase(sessionName)) { 482 + } else if ("Download".equalsIgnoreCase(sessionName)) {
483 // 获取指定的下载速度 483 // 获取指定的下载速度
484 Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true); 484 Vector sdpMediaDescriptions = sdp.getMediaDescriptions(true);
485 MediaDescription mediaDescription = null; 485 MediaDescription mediaDescription = null;
486 String downloadSpeed = "1"; 486 String downloadSpeed = "1";
487 if (sdpMediaDescriptions.size() > 0) { 487 if (sdpMediaDescriptions.size() > 0) {
488 - mediaDescription = (MediaDescription)sdpMediaDescriptions.get(0); 488 + mediaDescription = (MediaDescription) sdpMediaDescriptions.get(0);
489 } 489 }
490 if (mediaDescription != null) { 490 if (mediaDescription != null) {
491 downloadSpeed = mediaDescription.getAttribute("downloadspeed"); 491 downloadSpeed = mediaDescription.getAttribute("downloadspeed");
@@ -499,26 +499,26 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -499,26 +499,26 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
499 playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start), 499 playService.download(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
500 DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed), 500 DateUtil.formatter.format(end), Integer.parseInt(downloadSpeed),
501 (code, msg, data) -> { 501 (code, msg, data) -> {
502 - if (code == InviteErrorCode.SUCCESS.getCode()){ 502 + if (code == InviteErrorCode.SUCCESS.getCode()) {
503 hookEvent.run(code, msg, data); 503 hookEvent.run(code, msg, data);
504 - }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){ 504 + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
505 logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId); 505 logger.info("[录像下载]超时, 用户:{}, 通道:{}", username, channelId);
506 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); 506 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
507 errorEvent.run(code, msg, data); 507 errorEvent.run(code, msg, data);
508 - }else { 508 + } else {
509 errorEvent.run(code, msg, data); 509 errorEvent.run(code, msg, data);
510 } 510 }
511 }); 511 });
512 - }else { 512 + } else {
513 513
514 SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> { 514 SSRCInfo ssrcInfo = playService.play(mediaServerItem, device.getDeviceId(), channelId, ssrc, ((code, msg, data) -> {
515 - if (code == InviteErrorCode.SUCCESS.getCode()){ 515 + if (code == InviteErrorCode.SUCCESS.getCode()) {
516 hookEvent.run(code, msg, data); 516 hookEvent.run(code, msg, data);
517 - }else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()){ 517 + } else if (code == InviteErrorCode.ERROR_FOR_SIGNALLING_TIMEOUT.getCode() || code == InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode()) {
518 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId); 518 logger.info("[上级点播]超时, 用户:{}, 通道:{}", username, channelId);
519 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null); 519 redisCatchStorage.deleteSendRTPServer(platform.getServerGBId(), channelId, callIdHeader.getCallId(), null);
520 errorEvent.run(code, msg, data); 520 errorEvent.run(code, msg, data);
521 - }else { 521 + } else {
522 errorEvent.run(code, msg, data); 522 errorEvent.run(code, msg, data);
523 } 523 }
524 })); 524 }));
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
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java 100644 → 100755
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.getStreamId();  
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.getStreamId();
  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
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
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,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
13 import com.genersoft.iot.vmp.service.IDeviceService; 13 import com.genersoft.iot.vmp.service.IDeviceService;
14 import com.genersoft.iot.vmp.utils.DateUtil; 14 import com.genersoft.iot.vmp.utils.DateUtil;
15 import gov.nist.javax.sip.message.SIPRequest; 15 import gov.nist.javax.sip.message.SIPRequest;
  16 +import org.apache.commons.lang3.ObjectUtils;
16 import org.dom4j.Element; 17 import org.dom4j.Element;
17 import org.slf4j.Logger; 18 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory; 19 import org.slf4j.LoggerFactory;
@@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp @@ -68,7 +69,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp
68 } catch (SipException | InvalidArgumentException | ParseException e) { 69 } catch (SipException | InvalidArgumentException | ParseException e) {
69 logger.error("[命令发送失败] 心跳回复: {}", e.getMessage()); 70 logger.error("[命令发送失败] 心跳回复: {}", e.getMessage());
70 } 71 }
71 - if (DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L){ 72 + if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) {
72 logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); 73 logger.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId());
73 return; 74 return;
74 } 75 }
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
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 \ No newline at end of file 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,6 +21,7 @@ public class AssistRESTfulUtils {
21 21
22 private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); 22 private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class);
23 23
  24 +
24 public interface RequestCallback{ 25 public interface RequestCallback{
25 void run(JSONObject response); 26 void run(JSONObject response);
26 } 27 }
@@ -145,4 +146,25 @@ public class AssistRESTfulUtils { @@ -145,4 +146,25 @@ public class AssistRESTfulUtils {
145 return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); 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
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java 100644 → 100755
1 -package com.genersoft.iot.vmp.media.zlm;  
2 -  
3 -import com.alibaba.fastjson2.JSON;  
4 -import com.alibaba.fastjson2.JSONObject;  
5 -import com.genersoft.iot.vmp.common.InviteInfo;  
6 -import com.genersoft.iot.vmp.common.InviteSessionType;  
7 -import com.genersoft.iot.vmp.common.StreamInfo;  
8 -import com.genersoft.iot.vmp.common.VideoManagerConstants;  
9 -import com.genersoft.iot.vmp.conf.UserSetting;  
10 -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;  
11 -import com.genersoft.iot.vmp.gb28181.bean.*;  
12 -import com.genersoft.iot.vmp.gb28181.event.EventPublisher;  
13 -import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;  
14 -import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;  
15 -import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;  
16 -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;  
17 -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;  
18 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;  
19 -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;  
20 -import com.genersoft.iot.vmp.media.zlm.dto.HookType;  
21 -import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;  
22 -import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;  
23 -import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;  
24 -import com.genersoft.iot.vmp.media.zlm.dto.hook.*;  
25 -import com.genersoft.iot.vmp.service.*;  
26 -import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;  
27 -import com.genersoft.iot.vmp.service.bean.SSRCInfo;  
28 -import com.genersoft.iot.vmp.storager.IRedisCatchStorage;  
29 -import com.genersoft.iot.vmp.storager.IVideoManagerStorage;  
30 -import com.genersoft.iot.vmp.utils.DateUtil;  
31 -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;  
32 -import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;  
33 -import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;  
34 -import com.genersoft.iot.vmp.vmanager.bean.StreamContent;  
35 -import org.slf4j.Logger;  
36 -import org.slf4j.LoggerFactory;  
37 -import org.springframework.beans.factory.annotation.Autowired;  
38 -import org.springframework.beans.factory.annotation.Qualifier;  
39 -import org.springframework.data.redis.core.RedisTemplate;  
40 -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
41 -import org.springframework.util.ObjectUtils;  
42 -import org.springframework.web.bind.annotation.*;  
43 -import org.springframework.web.context.request.async.DeferredResult;  
44 -  
45 -import javax.servlet.http.HttpServletRequest;  
46 -import javax.sip.InvalidArgumentException;  
47 -import javax.sip.SipException;  
48 -import java.text.ParseException;  
49 -import java.util.HashMap;  
50 -import java.util.List;  
51 -import java.util.Map;  
52 -import java.util.UUID;  
53 -  
54 -/**  
55 - * @description:针对 ZLMediaServer的hook事件监听  
56 - * @author: swwheihei  
57 - * @date: 2020年5月8日 上午10:46:48  
58 - */  
59 -@RestController  
60 -@RequestMapping("/index/hook")  
61 -public class ZLMHttpHookListener {  
62 -  
63 - private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class);  
64 -  
65 - @Autowired  
66 - private SIPCommander cmder;  
67 -  
68 - @Autowired  
69 - private SIPCommanderFroPlatform commanderFroPlatform;  
70 -  
71 - @Autowired  
72 - private IPlayService playService;  
73 -  
74 - @Autowired  
75 - private IVideoManagerStorage storager;  
76 -  
77 - @Autowired  
78 - private IRedisCatchStorage redisCatchStorage;  
79 -  
80 - @Autowired  
81 - private IInviteStreamService inviteStreamService;  
82 -  
83 - @Autowired  
84 - private IDeviceService deviceService;  
85 -  
86 - @Autowired  
87 - private IMediaServerService mediaServerService;  
88 -  
89 - @Autowired  
90 - private IStreamProxyService streamProxyService;  
91 -  
92 - @Autowired  
93 - private DeferredResultHolder resultHolder;  
94 -  
95 - @Autowired  
96 - private IMediaService mediaService;  
97 -  
98 - @Autowired  
99 - private EventPublisher eventPublisher;  
100 -  
101 - @Autowired  
102 - private ZLMMediaListManager zlmMediaListManager;  
103 -  
104 - @Autowired  
105 - private ZlmHttpHookSubscribe subscribe;  
106 -  
107 - @Autowired  
108 - private UserSetting userSetting;  
109 -  
110 - @Autowired  
111 - private IUserService userService;  
112 -  
113 - @Autowired  
114 - private VideoStreamSessionManager sessionManager;  
115 -  
116 - @Autowired  
117 - private AssistRESTfulUtils assistRESTfulUtils;  
118 -  
119 - @Autowired  
120 - private SSRCFactory ssrcFactory;  
121 -  
122 - @Qualifier("taskExecutor")  
123 - @Autowired  
124 - private ThreadPoolTaskExecutor taskExecutor;  
125 -  
126 - @Autowired  
127 - private RedisTemplate<Object, Object> redisTemplate;  
128 -  
129 - /**  
130 - * 服务器定时上报时间,上报间隔可配置,默认10s上报一次  
131 - */  
132 - @ResponseBody  
133 -  
134 - @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")  
135 - public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {  
136 -  
137 -  
138 - taskExecutor.execute(() -> {  
139 - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);  
140 - if (subscribes != null && subscribes.size() > 0) {  
141 - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {  
142 - subscribe.response(null, param);  
143 - }  
144 - }  
145 - });  
146 - mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData());  
147 -  
148 - return HookResult.SUCCESS();  
149 - }  
150 -  
151 - /**  
152 - * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。  
153 - */  
154 - @ResponseBody  
155 -  
156 - @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")  
157 - public HookResult onPlay(@RequestBody OnPlayHookParam param) {  
158 - if (logger.isDebugEnabled()) {  
159 - logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param);  
160 - }  
161 - String mediaServerId = param.getMediaServerId();  
162 -  
163 - taskExecutor.execute(() -> {  
164 - JSONObject json = (JSONObject) JSON.toJSON(param);  
165 - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);  
166 - if (subscribe != null) {  
167 - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);  
168 - if (mediaInfo != null) {  
169 - subscribe.response(mediaInfo, param);  
170 - }  
171 - }  
172 - });  
173 - if (!"rtp".equals(param.getApp())) {  
174 - Map<String, String> paramMap = urlParamToMap(param.getParams());  
175 - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());  
176 - if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) {  
177 - return new HookResult(401, "Unauthorized");  
178 - }  
179 - }  
180 -  
181 - return HookResult.SUCCESS();  
182 - }  
183 -  
184 - /**  
185 - * rtsp/rtmp/rtp推流鉴权事件。  
186 - */  
187 - @ResponseBody  
188 - @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")  
189 - public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) {  
190 -  
191 - JSONObject json = (JSONObject) JSON.toJSON(param);  
192 -  
193 - logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param);  
194 -  
195 - String mediaServerId = json.getString("mediaServerId");  
196 - MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);  
197 - if (mediaInfo == null) {  
198 - return new HookResultForOnPublish(200, "success");  
199 - }  
200 - // 推流鉴权的处理  
201 - if (!"rtp".equals(param.getApp())) {  
202 - if (userSetting.getPushAuthority()) {  
203 - // 推流鉴权  
204 - if (param.getParams() == null) {  
205 - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");  
206 - return new HookResultForOnPublish(401, "Unauthorized");  
207 - }  
208 - Map<String, String> paramMap = urlParamToMap(param.getParams());  
209 - String sign = paramMap.get("sign");  
210 - if (sign == null) {  
211 - logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");  
212 - return new HookResultForOnPublish(401, "Unauthorized");  
213 - }  
214 - // 推流自定义播放鉴权码  
215 - String callId = paramMap.get("callId");  
216 - // 鉴权配置  
217 - boolean hasAuthority = userService.checkPushAuthority(callId, sign);  
218 - if (!hasAuthority) {  
219 - logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign);  
220 - return new HookResultForOnPublish(401, "Unauthorized");  
221 - }  
222 - StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);  
223 - streamAuthorityInfo.setCallId(callId);  
224 - streamAuthorityInfo.setSign(sign);  
225 - // 鉴权通过  
226 - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);  
227 - // 通知assist新的callId  
228 - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {  
229 - taskExecutor.execute(() -> {  
230 - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);  
231 - });  
232 - }  
233 - }  
234 - } else {  
235 - zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());  
236 - }  
237 -  
238 -  
239 - HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();  
240 - result.setEnable_audio(true);  
241 - taskExecutor.execute(() -> {  
242 - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);  
243 - if (subscribe != null) {  
244 - if (mediaInfo != null) {  
245 - subscribe.response(mediaInfo, param);  
246 - } else {  
247 - new HookResultForOnPublish(1, "zlm not register");  
248 - }  
249 - }  
250 - });  
251 -  
252 - // 是否录像  
253 - if ("rtp".equals(param.getApp())) {  
254 - result.setEnable_mp4(userSetting.getRecordSip());  
255 - } else {  
256 - result.setEnable_mp4(userSetting.isRecordPushLive());  
257 - }  
258 - // 替换流地址  
259 - if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) {  
260 - String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));;  
261 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);  
262 - if (inviteInfo != null) {  
263 - result.setStream_replace(inviteInfo.getStream());  
264 - logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream());  
265 - }  
266 - }  
267 - List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());  
268 - if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {  
269 - String deviceId = ssrcTransactionForAll.get(0).getDeviceId();  
270 - String channelId = ssrcTransactionForAll.get(0).getChannelId();  
271 - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);  
272 - if (deviceChannel != null) {  
273 - result.setEnable_audio(deviceChannel.isHasAudio());  
274 - }  
275 - // 如果是录像下载就设置视频间隔十秒  
276 - if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {  
277 - result.setMp4_max_second(10);  
278 - result.setEnable_mp4(true);  
279 - }  
280 - }  
281 - if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {  
282 - logger.info("推流时发现尚未设置录像路径,从assist服务中读取");  
283 - JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);  
284 - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {  
285 - JSONObject dataJson = info.getJSONObject("data");  
286 - if (dataJson != null) {  
287 - String recordPath = dataJson.getString("record");  
288 - userSetting.setRecordPath(recordPath);  
289 - result.setMp4_save_path(recordPath);  
290 - // 修改zlm中的录像路径  
291 - if (mediaInfo.isAutoConfig()) {  
292 - taskExecutor.execute(() -> {  
293 - mediaServerService.setZLMConfig(mediaInfo, false);  
294 - });  
295 - }  
296 - }  
297 - }  
298 - }  
299 - if (param.getApp().equalsIgnoreCase("rtp")) {  
300 - String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream();  
301 - OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey);  
302 -  
303 - String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream();  
304 - OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS);  
305 - if (otherRtpSendInfo != null || otherPsSendInfo != null) {  
306 - result.setEnable_mp4(true);  
307 - }  
308 - }  
309 - logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result);  
310 - return result;  
311 - }  
312 -  
313 -  
314 - /**  
315 - * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。  
316 - */  
317 - @ResponseBody  
318 - @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")  
319 - public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {  
320 -  
321 - if (param.isRegist()) {  
322 - logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
323 - } else {  
324 - logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
325 - }  
326 -  
327 -  
328 - JSONObject json = (JSONObject) JSON.toJSON(param);  
329 - taskExecutor.execute(() -> {  
330 - ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);  
331 - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());  
332 - if (mediaInfo == null) {  
333 - logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId());  
334 - return;  
335 - }  
336 - if (subscribe != null) {  
337 - subscribe.response(mediaInfo, param);  
338 - }  
339 -  
340 - List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();  
341 - // TODO 重构此处逻辑  
342 - boolean isPush = false;  
343 - if (param.isRegist()) {  
344 - // 处理流注册的鉴权信息  
345 - if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()  
346 - || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()  
347 - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {  
348 - isPush = true;  
349 - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());  
350 - if (streamAuthorityInfo == null) {  
351 - streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);  
352 - } else {  
353 - streamAuthorityInfo.setOriginType(param.getOriginType());  
354 - streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr());  
355 - }  
356 - redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);  
357 - }  
358 - } else {  
359 - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream());  
360 - }  
361 -  
362 - if ("rtsp".equals(param.getSchema())) {  
363 - // 更新流媒体负载信息  
364 - if (param.isRegist()) {  
365 - mediaServerService.addCount(param.getMediaServerId());  
366 - } else {  
367 - mediaServerService.removeCount(param.getMediaServerId());  
368 - }  
369 - // 设置拉流代理上线/离线  
370 - int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());  
371 - if (updateStatusResult > 0) {  
372 -  
373 - }  
374 -  
375 - if ("rtp".equals(param.getApp()) && !param.isRegist()) {  
376 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());  
377 - if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {  
378 - inviteStreamService.removeInviteInfo(inviteInfo);  
379 - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());  
380 - }  
381 - } else {  
382 - if (!"rtp".equals(param.getApp())) {  
383 - String type = OriginType.values()[param.getOriginType()].getType();  
384 - if (param.isRegist()) {  
385 - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(  
386 - param.getApp(), param.getStream());  
387 - String callId = null;  
388 - if (streamAuthorityInfo != null) {  
389 - callId = streamAuthorityInfo.getCallId();  
390 - }  
391 - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo,  
392 - param.getApp(), param.getStream(), tracks, callId);  
393 - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));  
394 - redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param);  
395 - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()  
396 - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()  
397 - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {  
398 - param.setSeverId(userSetting.getServerId());  
399 - zlmMediaListManager.addPush(param);  
400 - }  
401 - } else {  
402 - // 兼容流注销时类型从redis记录获取  
403 - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(  
404 - param.getApp(), param.getStream(), param.getMediaServerId());  
405 - if (onStreamChangedHookParam != null) {  
406 - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();  
407 - redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream());  
408 - }  
409 - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());  
410 - if (gbStream != null) {  
411 -// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);  
412 - }  
413 - zlmMediaListManager.removeMedia(param.getApp(), param.getStream());  
414 - }  
415 - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());  
416 - if (gbStream != null) {  
417 - if (userSetting.isUsePushingAsStatus()) {  
418 - eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF);  
419 - }  
420 - }  
421 - if (type != null) {  
422 - // 发送流变化redis消息  
423 - JSONObject jsonObject = new JSONObject();  
424 - jsonObject.put("serverId", userSetting.getServerId());  
425 - jsonObject.put("app", param.getApp());  
426 - jsonObject.put("stream", param.getStream());  
427 - jsonObject.put("register", param.isRegist());  
428 - jsonObject.put("mediaServerId", param.getMediaServerId());  
429 - redisCatchStorage.sendStreamChangeMsg(type, jsonObject);  
430 - }  
431 - }  
432 - }  
433 - if (!param.isRegist()) {  
434 - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());  
435 - if (sendRtpItems.size() > 0) {  
436 - for (SendRtpItem sendRtpItem : sendRtpItems) {  
437 - if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) {  
438 - String platformId = sendRtpItem.getPlatformId();  
439 - ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);  
440 - Device device = deviceService.getDevice(platformId);  
441 -  
442 - try {  
443 - if (platform != null) {  
444 - commanderFroPlatform.streamByeCmd(platform, sendRtpItem);  
445 - redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),  
446 - sendRtpItem.getCallId(), sendRtpItem.getStreamId());  
447 - } else {  
448 - cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());  
449 - }  
450 - } catch (SipException | InvalidArgumentException | ParseException |  
451 - SsrcTransactionNotFoundException e) {  
452 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
453 - }  
454 - }  
455 - }  
456 - }  
457 - }  
458 - }  
459 - });  
460 -  
461 - return HookResult.SUCCESS();  
462 - }  
463 -  
464 - /**  
465 - * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。  
466 - */  
467 - @ResponseBody  
468 - @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")  
469 - public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {  
470 -  
471 - logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),  
472 - param.getApp(), param.getStream());  
473 - JSONObject ret = new JSONObject();  
474 - ret.put("code", 0);  
475 - // 国标类型的流  
476 - if ("rtp".equals(param.getApp())) {  
477 - ret.put("close", userSetting.getStreamOnDemand());  
478 - // 国标流, 点播/录像回放/录像下载  
479 - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());  
480 - // 点播  
481 - if (inviteInfo != null) {  
482 - // 录像下载  
483 - if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {  
484 - ret.put("close", false);  
485 - return ret;  
486 - }  
487 - // 收到无人观看说明流也没有在往上级推送  
488 - if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {  
489 - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(  
490 - inviteInfo.getChannelId());  
491 - if (sendRtpItems.size() > 0) {  
492 - for (SendRtpItem sendRtpItem : sendRtpItems) {  
493 - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());  
494 - try {  
495 - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());  
496 - } catch (SipException | InvalidArgumentException | ParseException e) {  
497 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
498 - }  
499 - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),  
500 - sendRtpItem.getCallId(), sendRtpItem.getStreamId());  
501 - if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {  
502 - MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,  
503 - sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(),  
504 - sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());  
505 - messageForPushChannel.setPlatFormIndex(parentPlatform.getId());  
506 - redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);  
507 - }  
508 - }  
509 - }  
510 - }  
511 - Device device = deviceService.getDevice(inviteInfo.getDeviceId());  
512 - if (device != null) {  
513 - try {  
514 - // 多查询一次防止已经被处理了  
515 - InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),  
516 - inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());  
517 - if (info != null) {  
518 - cmder.streamByeCmd(device, inviteInfo.getChannelId(),  
519 - inviteInfo.getStream(), null);  
520 - }  
521 - } catch (InvalidArgumentException | ParseException | SipException |  
522 - SsrcTransactionNotFoundException e) {  
523 - logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());  
524 - }  
525 - }  
526 -  
527 - inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),  
528 - inviteInfo.getChannelId(), inviteInfo.getStream());  
529 - storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());  
530 - return ret;  
531 - }  
532 - } else {  
533 - // 非国标流 推流/拉流代理  
534 - // 拉流代理  
535 - StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());  
536 - if (streamProxyItem != null) {  
537 - if (streamProxyItem.isEnableRemoveNoneReader()) {  
538 - // 无人观看自动移除  
539 - ret.put("close", true);  
540 - streamProxyService.del(param.getApp(), param.getStream());  
541 - String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();  
542 - logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url);  
543 - } else if (streamProxyItem.isEnableDisableNoneReader()) {  
544 - // 无人观看停用  
545 - ret.put("close", true);  
546 - // 修改数据  
547 - streamProxyService.stop(param.getApp(), param.getStream());  
548 - } else {  
549 - // 无人观看不做处理  
550 - ret.put("close", false);  
551 - }  
552 - return ret;  
553 - }  
554 - // TODO 推流具有主动性,暂时不做处理  
555 -// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);  
556 -// if (streamPushItem != null) {  
557 -// // TODO 发送停止  
558 -//  
559 -// }  
560 - }  
561 - return ret;  
562 - }  
563 -  
564 - /**  
565 - * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。  
566 - */  
567 - @ResponseBody  
568 - @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")  
569 - public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {  
570 - logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
571 -  
572 - DeferredResult<HookResult> defaultResult = new DeferredResult<>();  
573 -  
574 - MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());  
575 - if (!userSetting.isAutoApplyPlay() || mediaInfo == null) {  
576 - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));  
577 - return defaultResult;  
578 - }  
579 -  
580 - if ("rtp".equals(param.getApp())) {  
581 - String[] s = param.getStream().split("_");  
582 - if ((s.length != 2 && s.length != 4)) {  
583 - defaultResult.setResult(HookResult.SUCCESS());  
584 - return defaultResult;  
585 - }  
586 - String deviceId = s[0];  
587 - String channelId = s[1];  
588 - Device device = redisCatchStorage.getDevice(deviceId);  
589 - if (device == null) {  
590 - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));  
591 - return defaultResult;  
592 - }  
593 - DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);  
594 - if (deviceChannel == null) {  
595 - defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));  
596 - return defaultResult;  
597 - }  
598 - if (s.length == 2) {  
599 - logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());  
600 -  
601 - RequestMessage msg = new RequestMessage();  
602 - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;  
603 - boolean exist = resultHolder.exist(key, null);  
604 - msg.setKey(key);  
605 - String uuid = UUID.randomUUID().toString();  
606 - msg.setId(uuid);  
607 - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());  
608 -  
609 - result.onTimeout(() -> {  
610 - logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");  
611 - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));  
612 - resultHolder.invokeResult(msg);  
613 - });  
614 -  
615 - resultHolder.put(key, uuid, result);  
616 -  
617 - if (!exist) {  
618 - playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {  
619 - msg.setData(new HookResult(code, message));  
620 - resultHolder.invokeResult(msg);  
621 - });  
622 - }  
623 - return result;  
624 - }else if(s.length == 4){  
625 - // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间  
626 - String startTimeStr = s[2];  
627 - String endTimeStr = s[3];  
628 - if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {  
629 - defaultResult.setResult(HookResult.SUCCESS());  
630 - return defaultResult;  
631 - }  
632 - String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);  
633 - String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);  
634 - logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}",  
635 - param.getMediaServerId(), param.getSchema(),  
636 - param.getApp(), param.getStream(),  
637 - startTime, endTime  
638 - );  
639 - RequestMessage msg = new RequestMessage();  
640 - String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;  
641 - boolean exist = resultHolder.exist(key, null);  
642 - msg.setKey(key);  
643 - String uuid = UUID.randomUUID().toString();  
644 - msg.setId(uuid);  
645 - DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());  
646 -  
647 - result.onTimeout(() -> {  
648 - logger.info("[ZLM HOOK] 回放流自动点播, 等待超时");  
649 - // 释放rtpserver  
650 - msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));  
651 - resultHolder.invokeResult(msg);  
652 - });  
653 -  
654 - resultHolder.put(key, uuid, result);  
655 -  
656 - if (!exist) {  
657 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,  
658 - device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());  
659 - playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {  
660 - msg.setData(new HookResult(code, message));  
661 - resultHolder.invokeResult(msg);  
662 - });  
663 - }  
664 - return result;  
665 - }else {  
666 - defaultResult.setResult(HookResult.SUCCESS());  
667 - return defaultResult;  
668 - }  
669 -  
670 - } else {  
671 - // 拉流代理  
672 - StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());  
673 - if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {  
674 - streamProxyService.start(param.getApp(), param.getStream());  
675 - }  
676 - DeferredResult<HookResult> result = new DeferredResult<>();  
677 - result.setResult(HookResult.SUCCESS());  
678 - return result;  
679 - }  
680 - }  
681 -  
682 - /**  
683 - * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。  
684 - */  
685 - @ResponseBody  
686 - @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")  
687 - public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) {  
688 -  
689 - jsonObject.put("ip", request.getRemoteAddr());  
690 - ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject);  
691 - zlmServerConfig.setIp(request.getRemoteAddr());  
692 - logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());  
693 - taskExecutor.execute(() -> {  
694 - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);  
695 - if (subscribes != null && subscribes.size() > 0) {  
696 - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {  
697 - subscribe.response(null, zlmServerConfig);  
698 - }  
699 - }  
700 - mediaServerService.zlmServerOnline(zlmServerConfig);  
701 - });  
702 -  
703 - return HookResult.SUCCESS();  
704 - }  
705 -  
706 - /**  
707 - * 发送rtp(startSendRtp)被动关闭时回调  
708 - */  
709 - @ResponseBody  
710 - @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")  
711 - public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) {  
712 -  
713 - logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());  
714 -  
715 - // 查找对应的上级推流,发送停止  
716 - if (!"rtp".equals(param.getApp())) {  
717 - return HookResult.SUCCESS();  
718 - }  
719 - taskExecutor.execute(() -> {  
720 - List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());  
721 - if (sendRtpItems.size() > 0) {  
722 - for (SendRtpItem sendRtpItem : sendRtpItems) {  
723 - ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());  
724 - ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());  
725 - try {  
726 - commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());  
727 - } catch (SipException | InvalidArgumentException | ParseException e) {  
728 - logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());  
729 - }  
730 - redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),  
731 - sendRtpItem.getCallId(), sendRtpItem.getStreamId());  
732 - }  
733 - }  
734 - });  
735 -  
736 - return HookResult.SUCCESS();  
737 - }  
738 -  
739 - /**  
740 - * rtpServer收流超时  
741 - */  
742 - @ResponseBody  
743 - @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")  
744 - public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) {  
745 - logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());  
746 -  
747 - taskExecutor.execute(() -> {  
748 - JSONObject json = (JSONObject) JSON.toJSON(param);  
749 - List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);  
750 - if (subscribes != null && subscribes.size() > 0) {  
751 - for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {  
752 - subscribe.response(null, param);  
753 - }  
754 - }  
755 - });  
756 -  
757 - return HookResult.SUCCESS();  
758 - }  
759 -  
760 - private Map<String, String> urlParamToMap(String params) {  
761 - HashMap<String, String> map = new HashMap<>();  
762 - if (ObjectUtils.isEmpty(params)) {  
763 - return map;  
764 - }  
765 - String[] paramsArray = params.split("&");  
766 - if (paramsArray.length == 0) {  
767 - return map;  
768 - }  
769 - for (String param : paramsArray) {  
770 - String[] paramArray = param.split("=");  
771 - if (paramArray.length == 2) {  
772 - map.put(paramArray[0], paramArray[1]);  
773 - }  
774 - }  
775 - return map;  
776 - }  
777 -} 1 +package com.genersoft.iot.vmp.media.zlm;
  2 +
  3 +import com.alibaba.fastjson2.JSON;
  4 +import com.alibaba.fastjson2.JSONObject;
  5 +import com.genersoft.iot.vmp.common.InviteInfo;
  6 +import com.genersoft.iot.vmp.common.InviteSessionType;
  7 +import com.genersoft.iot.vmp.common.StreamInfo;
  8 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  9 +import com.genersoft.iot.vmp.conf.UserSetting;
  10 +import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
  11 +import com.genersoft.iot.vmp.gb28181.bean.*;
  12 +import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
  13 +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent;
  14 +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory;
  15 +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
  16 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  17 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  18 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
  19 +import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommanderFroPlatform;
  20 +import com.genersoft.iot.vmp.media.zlm.dto.HookType;
  21 +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
  22 +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
  23 +import com.genersoft.iot.vmp.media.zlm.dto.StreamProxyItem;
  24 +import com.genersoft.iot.vmp.media.zlm.dto.hook.*;
  25 +import com.genersoft.iot.vmp.service.*;
  26 +import com.genersoft.iot.vmp.service.bean.MessageForPushChannel;
  27 +import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  28 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  29 +import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
  30 +import com.genersoft.iot.vmp.utils.DateUtil;
  31 +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  32 +import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo;
  33 +import com.genersoft.iot.vmp.vmanager.bean.OtherRtpSendInfo;
  34 +import com.genersoft.iot.vmp.vmanager.bean.StreamContent;
  35 +import org.slf4j.Logger;
  36 +import org.slf4j.LoggerFactory;
  37 +import org.springframework.beans.factory.annotation.Autowired;
  38 +import org.springframework.beans.factory.annotation.Qualifier;
  39 +import org.springframework.data.redis.core.RedisTemplate;
  40 +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  41 +import org.springframework.util.ObjectUtils;
  42 +import org.springframework.web.bind.annotation.*;
  43 +import org.springframework.web.context.request.async.DeferredResult;
  44 +
  45 +import javax.servlet.http.HttpServletRequest;
  46 +import javax.sip.InvalidArgumentException;
  47 +import javax.sip.SipException;
  48 +import java.text.ParseException;
  49 +import java.util.HashMap;
  50 +import java.util.List;
  51 +import java.util.Map;
  52 +import java.util.UUID;
  53 +
  54 +/**
  55 + * @description:针对 ZLMediaServer的hook事件监听
  56 + * @author: swwheihei
  57 + * @date: 2020年5月8日 上午10:46:48
  58 + */
  59 +@RestController
  60 +@RequestMapping("/index/hook")
  61 +public class ZLMHttpHookListener {
  62 +
  63 + private final static Logger logger = LoggerFactory.getLogger(ZLMHttpHookListener.class);
  64 +
  65 + @Autowired
  66 + private SIPCommander cmder;
  67 +
  68 + @Autowired
  69 + private SIPCommanderFroPlatform commanderFroPlatform;
  70 +
  71 + @Autowired
  72 + private IPlayService playService;
  73 +
  74 + @Autowired
  75 + private IVideoManagerStorage storager;
  76 +
  77 + @Autowired
  78 + private IRedisCatchStorage redisCatchStorage;
  79 +
  80 + @Autowired
  81 + private IInviteStreamService inviteStreamService;
  82 +
  83 + @Autowired
  84 + private IDeviceService deviceService;
  85 +
  86 + @Autowired
  87 + private IMediaServerService mediaServerService;
  88 +
  89 + @Autowired
  90 + private IStreamProxyService streamProxyService;
  91 +
  92 + @Autowired
  93 + private DeferredResultHolder resultHolder;
  94 +
  95 + @Autowired
  96 + private IMediaService mediaService;
  97 +
  98 + @Autowired
  99 + private EventPublisher eventPublisher;
  100 +
  101 + @Autowired
  102 + private ZLMMediaListManager zlmMediaListManager;
  103 +
  104 + @Autowired
  105 + private ZlmHttpHookSubscribe subscribe;
  106 +
  107 + @Autowired
  108 + private UserSetting userSetting;
  109 +
  110 + @Autowired
  111 + private IUserService userService;
  112 +
  113 + @Autowired
  114 + private VideoStreamSessionManager sessionManager;
  115 +
  116 + @Autowired
  117 + private AssistRESTfulUtils assistRESTfulUtils;
  118 +
  119 + @Autowired
  120 + private SSRCFactory ssrcFactory;
  121 +
  122 + @Qualifier("taskExecutor")
  123 + @Autowired
  124 + private ThreadPoolTaskExecutor taskExecutor;
  125 +
  126 + @Autowired
  127 + private RedisTemplate<Object, Object> redisTemplate;
  128 +
  129 + /**
  130 + * 服务器定时上报时间,上报间隔可配置,默认10s上报一次
  131 + */
  132 + @ResponseBody
  133 +
  134 + @PostMapping(value = "/on_server_keepalive", produces = "application/json;charset=UTF-8")
  135 + public HookResult onServerKeepalive(@RequestBody OnServerKeepaliveHookParam param) {
  136 +
  137 +
  138 + taskExecutor.execute(() -> {
  139 + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_keepalive);
  140 + if (subscribes != null && subscribes.size() > 0) {
  141 + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
  142 + subscribe.response(null, param);
  143 + }
  144 + }
  145 + });
  146 + mediaServerService.updateMediaServerKeepalive(param.getMediaServerId(), param.getData());
  147 +
  148 + return HookResult.SUCCESS();
  149 + }
  150 +
  151 + /**
  152 + * 播放器鉴权事件,rtsp/rtmp/http-flv/ws-flv/hls的播放都将触发此鉴权事件。
  153 + */
  154 + @ResponseBody
  155 +
  156 + @PostMapping(value = "/on_play", produces = "application/json;charset=UTF-8")
  157 + public HookResult onPlay(@RequestBody OnPlayHookParam param) {
  158 + if (logger.isDebugEnabled()) {
  159 + logger.debug("[ZLM HOOK] 播放鉴权:{}->{}" + param.getMediaServerId(), param);
  160 + }
  161 + String mediaServerId = param.getMediaServerId();
  162 +
  163 + taskExecutor.execute(() -> {
  164 + JSONObject json = (JSONObject) JSON.toJSON(param);
  165 + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_play, json);
  166 + if (subscribe != null) {
  167 + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  168 + if (mediaInfo != null) {
  169 + subscribe.response(mediaInfo, param);
  170 + }
  171 + }
  172 + });
  173 + if (!"rtp".equals(param.getApp())) {
  174 + Map<String, String> paramMap = urlParamToMap(param.getParams());
  175 + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
  176 + if (streamAuthorityInfo != null && streamAuthorityInfo.getCallId() != null && !streamAuthorityInfo.getCallId().equals(paramMap.get("callId"))) {
  177 + return new HookResult(401, "Unauthorized");
  178 + }
  179 + }
  180 +
  181 + return HookResult.SUCCESS();
  182 + }
  183 +
  184 + /**
  185 + * rtsp/rtmp/rtp推流鉴权事件。
  186 + */
  187 + @ResponseBody
  188 + @PostMapping(value = "/on_publish", produces = "application/json;charset=UTF-8")
  189 + public HookResultForOnPublish onPublish(@RequestBody OnPublishHookParam param) {
  190 +
  191 + JSONObject json = (JSONObject) JSON.toJSON(param);
  192 +
  193 + logger.info("[ZLM HOOK]推流鉴权:{}->{}", param.getMediaServerId(), param);
  194 +
  195 + String mediaServerId = json.getString("mediaServerId");
  196 + MediaServerItem mediaInfo = mediaServerService.getOne(mediaServerId);
  197 + if (mediaInfo == null) {
  198 + return new HookResultForOnPublish(200, "success");
  199 + }
  200 + // 推流鉴权的处理
  201 + if (!"rtp".equals(param.getApp())) {
  202 + if (userSetting.getPushAuthority()) {
  203 + // 推流鉴权
  204 + if (param.getParams() == null) {
  205 + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
  206 + return new HookResultForOnPublish(401, "Unauthorized");
  207 + }
  208 + Map<String, String> paramMap = urlParamToMap(param.getParams());
  209 + String sign = paramMap.get("sign");
  210 + if (sign == null) {
  211 + logger.info("推流鉴权失败: 缺少必要参数:sign=md5(user表的pushKey)");
  212 + return new HookResultForOnPublish(401, "Unauthorized");
  213 + }
  214 + // 推流自定义播放鉴权码
  215 + String callId = paramMap.get("callId");
  216 + // 鉴权配置
  217 + boolean hasAuthority = userService.checkPushAuthority(callId, sign);
  218 + if (!hasAuthority) {
  219 + logger.info("推流鉴权失败: sign 无权限: callId={}. sign={}", callId, sign);
  220 + return new HookResultForOnPublish(401, "Unauthorized");
  221 + }
  222 + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
  223 + streamAuthorityInfo.setCallId(callId);
  224 + streamAuthorityInfo.setSign(sign);
  225 + // 鉴权通过
  226 + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
  227 + // 通知assist新的callId
  228 + if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) {
  229 + taskExecutor.execute(() -> {
  230 + assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null);
  231 + });
  232 + }
  233 + }
  234 + } else {
  235 + zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId());
  236 + }
  237 +
  238 +
  239 + HookResultForOnPublish result = HookResultForOnPublish.SUCCESS();
  240 + result.setEnable_audio(true);
  241 + taskExecutor.execute(() -> {
  242 + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json);
  243 + if (subscribe != null) {
  244 + if (mediaInfo != null) {
  245 + subscribe.response(mediaInfo, param);
  246 + } else {
  247 + new HookResultForOnPublish(1, "zlm not register");
  248 + }
  249 + }
  250 + });
  251 +
  252 + // 是否录像
  253 + if ("rtp".equals(param.getApp())) {
  254 + result.setEnable_mp4(userSetting.getRecordSip());
  255 + } else {
  256 + result.setEnable_mp4(userSetting.isRecordPushLive());
  257 + }
  258 + // 替换流地址
  259 + if ("rtp".equals(param.getApp()) && !mediaInfo.isRtpEnable()) {
  260 + String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16));;
  261 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc);
  262 + if (inviteInfo != null) {
  263 + result.setStream_replace(inviteInfo.getStream());
  264 + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream());
  265 + }
  266 + }
  267 + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream());
  268 + if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) {
  269 + String deviceId = ssrcTransactionForAll.get(0).getDeviceId();
  270 + String channelId = ssrcTransactionForAll.get(0).getChannelId();
  271 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  272 + if (deviceChannel != null) {
  273 + result.setEnable_audio(deviceChannel.isHasAudio());
  274 + }
  275 + // 如果是录像下载就设置视频间隔十秒
  276 + if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) {
  277 + result.setMp4_max_second(10);
  278 + result.setEnable_mp4(true);
  279 + }
  280 + }
  281 + if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) {
  282 + logger.info("推流时发现尚未设置录像路径,从assist服务中读取");
  283 + JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null);
  284 + if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) {
  285 + JSONObject dataJson = info.getJSONObject("data");
  286 + if (dataJson != null) {
  287 + String recordPath = dataJson.getString("record");
  288 + userSetting.setRecordPath(recordPath);
  289 + result.setMp4_save_path(recordPath);
  290 + // 修改zlm中的录像路径
  291 + if (mediaInfo.isAutoConfig()) {
  292 + taskExecutor.execute(() -> {
  293 + mediaServerService.setZLMConfig(mediaInfo, false);
  294 + });
  295 + }
  296 + }
  297 + }
  298 + }
  299 + if (param.getApp().equalsIgnoreCase("rtp")) {
  300 + String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream();
  301 + OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey);
  302 +
  303 + String receiveKeyForPS = VideoManagerConstants.WVP_OTHER_RECEIVE_PS_INFO + userSetting.getServerId() + "_" + param.getStream();
  304 + OtherPsSendInfo otherPsSendInfo = (OtherPsSendInfo)redisTemplate.opsForValue().get(receiveKeyForPS);
  305 + if (otherRtpSendInfo != null || otherPsSendInfo != null) {
  306 + result.setEnable_mp4(true);
  307 + }
  308 + }
  309 + logger.info("[ZLM HOOK]推流鉴权 响应:{}->{}->>>>{}", param.getMediaServerId(), param, result);
  310 + return result;
  311 + }
  312 +
  313 +
  314 + /**
  315 + * rtsp/rtmp流注册或注销时触发此事件;此事件对回复不敏感。
  316 + */
  317 + @ResponseBody
  318 + @PostMapping(value = "/on_stream_changed", produces = "application/json;charset=UTF-8")
  319 + public HookResult onStreamChanged(@RequestBody OnStreamChangedHookParam param) {
  320 +
  321 + if (param.isRegist()) {
  322 + logger.info("[ZLM HOOK] 流注册, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  323 + } else {
  324 + logger.info("[ZLM HOOK] 流注销, {}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  325 + }
  326 +
  327 +
  328 + JSONObject json = (JSONObject) JSON.toJSON(param);
  329 + taskExecutor.execute(() -> {
  330 + ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_stream_changed, json);
  331 + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
  332 + if (mediaInfo == null) {
  333 + logger.info("[ZLM HOOK] 流变化未找到ZLM, {}", param.getMediaServerId());
  334 + return;
  335 + }
  336 + if (subscribe != null) {
  337 + subscribe.response(mediaInfo, param);
  338 + }
  339 +
  340 + List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks();
  341 + // TODO 重构此处逻辑
  342 + boolean isPush = false;
  343 + if (param.isRegist()) {
  344 + // 处理流注册的鉴权信息
  345 + if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
  346 + || param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
  347 + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
  348 + isPush = true;
  349 + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream());
  350 + if (streamAuthorityInfo == null) {
  351 + streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param);
  352 + } else {
  353 + streamAuthorityInfo.setOriginType(param.getOriginType());
  354 + streamAuthorityInfo.setOriginTypeStr(param.getOriginTypeStr());
  355 + }
  356 + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo);
  357 + }
  358 + } else {
  359 + redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream());
  360 + }
  361 +
  362 + if ("rtsp".equals(param.getSchema())) {
  363 + // 更新流媒体负载信息
  364 + if (param.isRegist()) {
  365 + mediaServerService.addCount(param.getMediaServerId());
  366 + } else {
  367 + mediaServerService.removeCount(param.getMediaServerId());
  368 + }
  369 + // 设置拉流代理上线/离线
  370 + int updateStatusResult = streamProxyService.updateStatus(param.isRegist(), param.getApp(), param.getStream());
  371 + if (updateStatusResult > 0) {
  372 +
  373 + }
  374 +
  375 + if ("rtp".equals(param.getApp()) && !param.isRegist()) {
  376 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
  377 + if (inviteInfo != null && (inviteInfo.getType() == InviteSessionType.PLAY || inviteInfo.getType() == InviteSessionType.PLAYBACK)) {
  378 + inviteStreamService.removeInviteInfo(inviteInfo);
  379 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
  380 + }
  381 + } else {
  382 + if (!"rtp".equals(param.getApp())) {
  383 + String type = OriginType.values()[param.getOriginType()].getType();
  384 + if (param.isRegist()) {
  385 + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(
  386 + param.getApp(), param.getStream());
  387 + String callId = null;
  388 + if (streamAuthorityInfo != null) {
  389 + callId = streamAuthorityInfo.getCallId();
  390 + }
  391 + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo,
  392 + param.getApp(), param.getStream(), tracks, callId);
  393 + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream));
  394 + redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param);
  395 + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal()
  396 + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal()
  397 + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) {
  398 + param.setSeverId(userSetting.getServerId());
  399 + zlmMediaListManager.addPush(param);
  400 + }
  401 + } else {
  402 + // 兼容流注销时类型从redis记录获取
  403 + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo(
  404 + param.getApp(), param.getStream(), param.getMediaServerId());
  405 + if (onStreamChangedHookParam != null) {
  406 + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType();
  407 + redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream());
  408 + }
  409 + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
  410 + if (gbStream != null) {
  411 +// eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF);
  412 + }
  413 + zlmMediaListManager.removeMedia(param.getApp(), param.getStream());
  414 + }
  415 + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream());
  416 + if (gbStream != null) {
  417 + if (userSetting.isUsePushingAsStatus()) {
  418 + eventPublisher.catalogEventPublishForStream(null, gbStream, param.isRegist()?CatalogEvent.ON:CatalogEvent.OFF);
  419 + }
  420 + }
  421 + if (type != null) {
  422 + // 发送流变化redis消息
  423 + JSONObject jsonObject = new JSONObject();
  424 + jsonObject.put("serverId", userSetting.getServerId());
  425 + jsonObject.put("app", param.getApp());
  426 + jsonObject.put("stream", param.getStream());
  427 + jsonObject.put("register", param.isRegist());
  428 + jsonObject.put("mediaServerId", param.getMediaServerId());
  429 + redisCatchStorage.sendStreamChangeMsg(type, jsonObject);
  430 + }
  431 + }
  432 + }
  433 + if (!param.isRegist()) {
  434 + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
  435 + if (sendRtpItems.size() > 0) {
  436 + for (SendRtpItem sendRtpItem : sendRtpItems) {
  437 + if (sendRtpItem != null && sendRtpItem.getApp().equals(param.getApp())) {
  438 + String platformId = sendRtpItem.getPlatformId();
  439 + ParentPlatform platform = storager.queryParentPlatByServerGBId(platformId);
  440 + Device device = deviceService.getDevice(platformId);
  441 +
  442 + try {
  443 + if (platform != null) {
  444 + commanderFroPlatform.streamByeCmd(platform, sendRtpItem);
  445 + redisCatchStorage.deleteSendRTPServer(platformId, sendRtpItem.getChannelId(),
  446 + sendRtpItem.getCallId(), sendRtpItem.getStreamId());
  447 + } else {
  448 + cmder.streamByeCmd(device, sendRtpItem.getChannelId(), param.getStream(), sendRtpItem.getCallId());
  449 + }
  450 + } catch (SipException | InvalidArgumentException | ParseException |
  451 + SsrcTransactionNotFoundException e) {
  452 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  453 + }
  454 + }
  455 + }
  456 + }
  457 + }
  458 + }
  459 + });
  460 +
  461 + return HookResult.SUCCESS();
  462 + }
  463 +
  464 + /**
  465 + * 流无人观看时事件,用户可以通过此事件选择是否关闭无人看的流。
  466 + */
  467 + @ResponseBody
  468 + @PostMapping(value = "/on_stream_none_reader", produces = "application/json;charset=UTF-8")
  469 + public JSONObject onStreamNoneReader(@RequestBody OnStreamNoneReaderHookParam param) {
  470 +
  471 + logger.info("[ZLM HOOK]流无人观看:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(),
  472 + param.getApp(), param.getStream());
  473 + JSONObject ret = new JSONObject();
  474 + ret.put("code", 0);
  475 + // 国标类型的流
  476 + if ("rtp".equals(param.getApp())) {
  477 + ret.put("close", userSetting.getStreamOnDemand());
  478 + // 国标流, 点播/录像回放/录像下载
  479 + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, param.getStream());
  480 + // 点播
  481 + if (inviteInfo != null) {
  482 + // 录像下载
  483 + if (inviteInfo.getType() == InviteSessionType.DOWNLOAD) {
  484 + ret.put("close", false);
  485 + return ret;
  486 + }
  487 + // 收到无人观看说明流也没有在往上级推送
  488 + if (redisCatchStorage.isChannelSendingRTP(inviteInfo.getChannelId())) {
  489 + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByChnnelId(
  490 + inviteInfo.getChannelId());
  491 + if (sendRtpItems.size() > 0) {
  492 + for (SendRtpItem sendRtpItem : sendRtpItems) {
  493 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
  494 + try {
  495 + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
  496 + } catch (SipException | InvalidArgumentException | ParseException e) {
  497 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  498 + }
  499 + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
  500 + sendRtpItem.getCallId(), sendRtpItem.getStreamId());
  501 + if (InviteStreamType.PUSH == sendRtpItem.getPlayType()) {
  502 + MessageForPushChannel messageForPushChannel = MessageForPushChannel.getInstance(0,
  503 + sendRtpItem.getApp(), sendRtpItem.getStreamId(), sendRtpItem.getChannelId(),
  504 + sendRtpItem.getPlatformId(), parentPlatform.getName(), userSetting.getServerId(), sendRtpItem.getMediaServerId());
  505 + messageForPushChannel.setPlatFormIndex(parentPlatform.getId());
  506 + redisCatchStorage.sendPlatformStopPlayMsg(messageForPushChannel);
  507 + }
  508 + }
  509 + }
  510 + }
  511 + Device device = deviceService.getDevice(inviteInfo.getDeviceId());
  512 + if (device != null) {
  513 + try {
  514 + // 多查询一次防止已经被处理了
  515 + InviteInfo info = inviteStreamService.getInviteInfo(inviteInfo.getType(),
  516 + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), inviteInfo.getStream());
  517 + if (info != null) {
  518 + cmder.streamByeCmd(device, inviteInfo.getChannelId(),
  519 + inviteInfo.getStream(), null);
  520 + }
  521 + } catch (InvalidArgumentException | ParseException | SipException |
  522 + SsrcTransactionNotFoundException e) {
  523 + logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage());
  524 + }
  525 + }
  526 +
  527 + inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(),
  528 + inviteInfo.getChannelId(), inviteInfo.getStream());
  529 + storager.stopPlay(inviteInfo.getDeviceId(), inviteInfo.getChannelId());
  530 + return ret;
  531 + }
  532 + } else {
  533 + // 非国标流 推流/拉流代理
  534 + // 拉流代理
  535 + StreamProxyItem streamProxyItem = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
  536 + if (streamProxyItem != null) {
  537 + if (streamProxyItem.isEnableRemoveNoneReader()) {
  538 + // 无人观看自动移除
  539 + ret.put("close", true);
  540 + streamProxyService.del(param.getApp(), param.getStream());
  541 + String url = streamProxyItem.getUrl() != null ? streamProxyItem.getUrl() : streamProxyItem.getSrcUrl();
  542 + logger.info("[{}/{}]<-[{}] 拉流代理无人观看已经移除", param.getApp(), param.getStream(), url);
  543 + } else if (streamProxyItem.isEnableDisableNoneReader()) {
  544 + // 无人观看停用
  545 + ret.put("close", true);
  546 + // 修改数据
  547 + streamProxyService.stop(param.getApp(), param.getStream());
  548 + } else {
  549 + // 无人观看不做处理
  550 + ret.put("close", false);
  551 + }
  552 + return ret;
  553 + }
  554 + // TODO 推流具有主动性,暂时不做处理
  555 +// StreamPushItem streamPushItem = streamPushService.getPush(app, streamId);
  556 +// if (streamPushItem != null) {
  557 +// // TODO 发送停止
  558 +//
  559 +// }
  560 + }
  561 + return ret;
  562 + }
  563 +
  564 + /**
  565 + * 流未找到事件,用户可以在此事件触发时,立即去拉流,这样可以实现按需拉流;此事件对回复不敏感。
  566 + */
  567 + @ResponseBody
  568 + @PostMapping(value = "/on_stream_not_found", produces = "application/json;charset=UTF-8")
  569 + public DeferredResult<HookResult> onStreamNotFound(@RequestBody OnStreamNotFoundHookParam param) {
  570 + logger.info("[ZLM HOOK] 流未找到:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  571 +
  572 + DeferredResult<HookResult> defaultResult = new DeferredResult<>();
  573 +
  574 + MediaServerItem mediaInfo = mediaServerService.getOne(param.getMediaServerId());
  575 + if (!userSetting.isAutoApplyPlay() || mediaInfo == null) {
  576 + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
  577 + return defaultResult;
  578 + }
  579 +
  580 + if ("rtp".equals(param.getApp())) {
  581 + String[] s = param.getStream().split("_");
  582 + if ((s.length != 2 && s.length != 4)) {
  583 + defaultResult.setResult(HookResult.SUCCESS());
  584 + return defaultResult;
  585 + }
  586 + String deviceId = s[0];
  587 + String channelId = s[1];
  588 + Device device = redisCatchStorage.getDevice(deviceId);
  589 + if (device == null) {
  590 + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
  591 + return defaultResult;
  592 + }
  593 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  594 + if (deviceChannel == null) {
  595 + defaultResult.setResult(new HookResult(ErrorCode.ERROR404.getCode(), ErrorCode.ERROR404.getMsg()));
  596 + return defaultResult;
  597 + }
  598 + if (s.length == 2) {
  599 + logger.info("[ZLM HOOK] 预览流未找到, 发起自动点播:{}->{}->{}/{}", param.getMediaServerId(), param.getSchema(), param.getApp(), param.getStream());
  600 +
  601 + RequestMessage msg = new RequestMessage();
  602 + String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId;
  603 + boolean exist = resultHolder.exist(key, null);
  604 + msg.setKey(key);
  605 + String uuid = UUID.randomUUID().toString();
  606 + msg.setId(uuid);
  607 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  608 +
  609 + result.onTimeout(() -> {
  610 + logger.info("[ZLM HOOK] 预览流自动点播, 等待超时");
  611 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
  612 + resultHolder.invokeResult(msg);
  613 + });
  614 +
  615 + resultHolder.put(key, uuid, result);
  616 +
  617 + if (!exist) {
  618 + playService.play(mediaInfo, deviceId, channelId, null, (code, message, data) -> {
  619 + msg.setData(new HookResult(code, message));
  620 + resultHolder.invokeResult(msg);
  621 + });
  622 + }
  623 + return result;
  624 + }else if(s.length == 4){
  625 + // 此时为录像回放, 录像回放格式为> 设备ID_通道ID_开始时间_结束时间
  626 + String startTimeStr = s[2];
  627 + String endTimeStr = s[3];
  628 + if (startTimeStr == null || endTimeStr == null || startTimeStr.length() != 14 || endTimeStr.length() != 14) {
  629 + defaultResult.setResult(HookResult.SUCCESS());
  630 + return defaultResult;
  631 + }
  632 + String startTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(startTimeStr);
  633 + String endTime = DateUtil.urlToyyyy_MM_dd_HH_mm_ss(endTimeStr);
  634 + logger.info("[ZLM HOOK] 回放流未找到, 发起自动点播:{}->{}->{}/{}-{}-{}",
  635 + param.getMediaServerId(), param.getSchema(),
  636 + param.getApp(), param.getStream(),
  637 + startTime, endTime
  638 + );
  639 + RequestMessage msg = new RequestMessage();
  640 + String key = DeferredResultHolder.CALLBACK_CMD_PLAYBACK + deviceId + channelId;
  641 + boolean exist = resultHolder.exist(key, null);
  642 + msg.setKey(key);
  643 + String uuid = UUID.randomUUID().toString();
  644 + msg.setId(uuid);
  645 + DeferredResult<HookResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
  646 +
  647 + result.onTimeout(() -> {
  648 + logger.info("[ZLM HOOK] 回放流自动点播, 等待超时");
  649 + // 释放rtpserver
  650 + msg.setData(new HookResult(ErrorCode.ERROR100.getCode(), "点播超时"));
  651 + resultHolder.invokeResult(msg);
  652 + });
  653 +
  654 + resultHolder.put(key, uuid, result);
  655 +
  656 + if (!exist) {
  657 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaInfo, param.getStream(), null,
  658 + device.isSsrcCheck(), true, 0, false, device.getStreamModeForParam());
  659 + playService.playBack(mediaInfo, ssrcInfo, deviceId, channelId, startTime, endTime, (code, message, data) -> {
  660 + msg.setData(new HookResult(code, message));
  661 + resultHolder.invokeResult(msg);
  662 + });
  663 + }
  664 + return result;
  665 + }else {
  666 + defaultResult.setResult(HookResult.SUCCESS());
  667 + return defaultResult;
  668 + }
  669 +
  670 + } else {
  671 + // 拉流代理
  672 + StreamProxyItem streamProxyByAppAndStream = streamProxyService.getStreamProxyByAppAndStream(param.getApp(), param.getStream());
  673 + if (streamProxyByAppAndStream != null && streamProxyByAppAndStream.isEnableDisableNoneReader()) {
  674 + streamProxyService.start(param.getApp(), param.getStream());
  675 + }
  676 + DeferredResult<HookResult> result = new DeferredResult<>();
  677 + result.setResult(HookResult.SUCCESS());
  678 + return result;
  679 + }
  680 + }
  681 +
  682 + /**
  683 + * 服务器启动事件,可以用于监听服务器崩溃重启;此事件对回复不敏感。
  684 + */
  685 + @ResponseBody
  686 + @PostMapping(value = "/on_server_started", produces = "application/json;charset=UTF-8")
  687 + public HookResult onServerStarted(HttpServletRequest request, @RequestBody JSONObject jsonObject) {
  688 +
  689 + jsonObject.put("ip", request.getRemoteAddr());
  690 + ZLMServerConfig zlmServerConfig = JSON.to(ZLMServerConfig.class, jsonObject);
  691 + zlmServerConfig.setIp(request.getRemoteAddr());
  692 + logger.info("[ZLM HOOK] zlm 启动 " + zlmServerConfig.getGeneralMediaServerId());
  693 + taskExecutor.execute(() -> {
  694 + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_server_started);
  695 + if (subscribes != null && subscribes.size() > 0) {
  696 + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
  697 + subscribe.response(null, zlmServerConfig);
  698 + }
  699 + }
  700 + mediaServerService.zlmServerOnline(zlmServerConfig);
  701 + });
  702 +
  703 + return HookResult.SUCCESS();
  704 + }
  705 +
  706 + /**
  707 + * 发送rtp(startSendRtp)被动关闭时回调
  708 + */
  709 + @ResponseBody
  710 + @PostMapping(value = "/on_send_rtp_stopped", produces = "application/json;charset=UTF-8")
  711 + public HookResult onSendRtpStopped(HttpServletRequest request, @RequestBody OnSendRtpStoppedHookParam param) {
  712 +
  713 + logger.info("[ZLM HOOK] rtp发送关闭:{}->{}/{}", param.getMediaServerId(), param.getApp(), param.getStream());
  714 +
  715 + // 查找对应的上级推流,发送停止
  716 + if (!"rtp".equals(param.getApp())) {
  717 + return HookResult.SUCCESS();
  718 + }
  719 + taskExecutor.execute(() -> {
  720 + List<SendRtpItem> sendRtpItems = redisCatchStorage.querySendRTPServerByStream(param.getStream());
  721 + if (sendRtpItems.size() > 0) {
  722 + for (SendRtpItem sendRtpItem : sendRtpItems) {
  723 + ParentPlatform parentPlatform = storager.queryParentPlatByServerGBId(sendRtpItem.getPlatformId());
  724 + ssrcFactory.releaseSsrc(sendRtpItem.getMediaServerId(), sendRtpItem.getSsrc());
  725 + try {
  726 + commanderFroPlatform.streamByeCmd(parentPlatform, sendRtpItem.getCallId());
  727 + } catch (SipException | InvalidArgumentException | ParseException e) {
  728 + logger.error("[命令发送失败] 国标级联 发送BYE: {}", e.getMessage());
  729 + }
  730 + redisCatchStorage.deleteSendRTPServer(parentPlatform.getServerGBId(), sendRtpItem.getChannelId(),
  731 + sendRtpItem.getCallId(), sendRtpItem.getStreamId());
  732 + }
  733 + }
  734 + });
  735 +
  736 + return HookResult.SUCCESS();
  737 + }
  738 +
  739 + /**
  740 + * rtpServer收流超时
  741 + */
  742 + @ResponseBody
  743 + @PostMapping(value = "/on_rtp_server_timeout", produces = "application/json;charset=UTF-8")
  744 + public HookResult onRtpServerTimeout(HttpServletRequest request, @RequestBody OnRtpServerTimeoutHookParam param) {
  745 + logger.info("[ZLM HOOK] rtpServer收流超时:{}->{}({})", param.getMediaServerId(), param.getStream_id(), param.getSsrc());
  746 +
  747 + taskExecutor.execute(() -> {
  748 + JSONObject json = (JSONObject) JSON.toJSON(param);
  749 + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout);
  750 + if (subscribes != null && subscribes.size() > 0) {
  751 + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) {
  752 + subscribe.response(null, param);
  753 + }
  754 + }
  755 + });
  756 +
  757 + return HookResult.SUCCESS();
  758 + }
  759 +
  760 + private Map<String, String> urlParamToMap(String params) {
  761 + HashMap<String, String> map = new HashMap<>();
  762 + if (ObjectUtils.isEmpty(params)) {
  763 + return map;
  764 + }
  765 + String[] paramsArray = params.split("&");
  766 + if (paramsArray.length == 0) {
  767 + return map;
  768 + }
  769 + for (String param : paramsArray) {
  770 + String[] paramArray = param.split("=");
  771 + if (paramArray.length == 2) {
  772 + map.put(paramArray[0], paramArray[1]);
  773 + }
  774 + }
  775 + return map;
  776 + }
  777 +}
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,7 +42,7 @@ public class ZLMServerFactory {
42 * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。 42 * @param tcpMode 0/null udp 模式,1 tcp 被动模式, 2 tcp 主动模式。
43 * @return 43 * @return
44 */ 44 */
45 - public int createRTPServer(MediaServerItem mediaServerItem, String streamId, int ssrc, Integer port, Boolean reUsePort, Integer tcpMode) { 45 + public int createRTPServer(MediaServerItem mediaServerItem, String streamId, long ssrc, Integer port, Boolean reUsePort, Integer tcpMode) {
46 int result = -1; 46 int result = -1;
47 // 查询此rtp server 是否已经存在 47 // 查询此rtp server 是否已经存在
48 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, streamId); 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 +6,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem;
6 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData; 6 import com.genersoft.iot.vmp.media.zlm.dto.ServerKeepaliveData;
7 import com.genersoft.iot.vmp.service.bean.MediaServerLoad; 7 import com.genersoft.iot.vmp.service.bean.MediaServerLoad;
8 import com.genersoft.iot.vmp.service.bean.SSRCInfo; 8 import com.genersoft.iot.vmp.service.bean.SSRCInfo;
  9 +import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
9 10
10 import java.util.List; 11 import java.util.List;
11 12
@@ -93,4 +94,14 @@ public interface IMediaServerService { @@ -93,4 +94,14 @@ public interface IMediaServerService {
93 * @return 94 * @return
94 */ 95 */
95 MediaServerLoad getLoad(MediaServerItem mediaServerItem); 96 MediaServerLoad getLoad(MediaServerItem mediaServerItem);
  97 +
  98 + /**
  99 + * 按时间查找录像文件
  100 + */
  101 + List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems);
  102 +
  103 + /**
  104 + * 查找存在录像文件的时间
  105 + */
  106 + List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems);
96 } 107 }
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
@@ -210,7 +210,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -210,7 +210,7 @@ public class DeviceServiceImpl implements IDeviceService {
210 redisCatchStorage.updateDevice(device); 210 redisCatchStorage.updateDevice(device);
211 deviceMapper.update(device); 211 deviceMapper.update(device);
212 //进行通道离线 212 //进行通道离线
213 - deviceChannelMapper.offlineByDeviceId(deviceId); 213 +// deviceChannelMapper.offlineByDeviceId(deviceId);
214 // 离线释放所有ssrc 214 // 离线释放所有ssrc
215 List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(deviceId, null, null, null); 215 List<SsrcTransaction> ssrcTransactions = streamSession.getSsrcTransactionForAll(deviceId, null, null, null);
216 if (ssrcTransactions != null && ssrcTransactions.size() > 0) { 216 if (ssrcTransactions != null && ssrcTransactions.size() > 0) {
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,23 +24,30 @@ import com.genersoft.iot.vmp.utils.DateUtil;
24 import com.genersoft.iot.vmp.utils.JsonUtil; 24 import com.genersoft.iot.vmp.utils.JsonUtil;
25 import com.genersoft.iot.vmp.utils.redis.RedisUtil; 25 import com.genersoft.iot.vmp.utils.redis.RedisUtil;
26 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; 26 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
  27 +import com.genersoft.iot.vmp.vmanager.bean.RecordFile;
27 import okhttp3.OkHttpClient; 28 import okhttp3.OkHttpClient;
28 import okhttp3.Request; 29 import okhttp3.Request;
29 import okhttp3.Response; 30 import okhttp3.Response;
30 import org.slf4j.Logger; 31 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory; 32 import org.slf4j.LoggerFactory;
32 import org.springframework.beans.factory.annotation.Autowired; 33 import org.springframework.beans.factory.annotation.Autowired;
  34 +import org.springframework.beans.factory.annotation.Qualifier;
33 import org.springframework.beans.factory.annotation.Value; 35 import org.springframework.beans.factory.annotation.Value;
34 import org.springframework.data.redis.core.RedisTemplate; 36 import org.springframework.data.redis.core.RedisTemplate;
35 import org.springframework.jdbc.datasource.DataSourceTransactionManager; 37 import org.springframework.jdbc.datasource.DataSourceTransactionManager;
  38 +import org.springframework.scheduling.annotation.Async;
  39 +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
36 import org.springframework.stereotype.Service; 40 import org.springframework.stereotype.Service;
37 import org.springframework.transaction.TransactionDefinition; 41 import org.springframework.transaction.TransactionDefinition;
38 import org.springframework.transaction.TransactionStatus; 42 import org.springframework.transaction.TransactionStatus;
  43 +import org.springframework.util.Assert;
39 import org.springframework.util.ObjectUtils; 44 import org.springframework.util.ObjectUtils;
40 45
41 import java.io.File; 46 import java.io.File;
42 import java.time.LocalDateTime; 47 import java.time.LocalDateTime;
43 import java.util.*; 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,6 +111,11 @@ public class MediaServerServiceImpl implements IMediaServerService {
104 @Autowired 111 @Autowired
105 private RedisTemplate<Object, Object> redisTemplate; 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 * 初始化
@@ -149,7 +161,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -149,7 +161,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
149 } 161 }
150 162
151 if (streamId == null) { 163 if (streamId == null) {
152 - streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); 164 + streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase();
153 } 165 }
154 int ssrcCheckParam = 0; 166 int ssrcCheckParam = 0;
155 if (ssrcCheck && tcpMode > 1) { 167 if (ssrcCheck && tcpMode > 1) {
@@ -158,7 +170,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -158,7 +170,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
158 } 170 }
159 int rtpServerPort; 171 int rtpServerPort;
160 if (mediaServerItem.isRtpEnable()) { 172 if (mediaServerItem.isRtpEnable()) {
161 - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0)?Integer.parseInt(ssrc):0, port, reUsePort, tcpMode); 173 + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, reUsePort, tcpMode);
162 } else { 174 } else {
163 rtpServerPort = mediaServerItem.getRtpProxyPort(); 175 rtpServerPort = mediaServerItem.getRtpProxyPort();
164 } 176 }
@@ -749,4 +761,89 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -749,4 +761,89 @@ public class MediaServerServiceImpl implements IMediaServerService {
749 return result; 761 return result;
750 } 762 }
751 763
  764 + @Override
  765 + public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) {
  766 + Assert.notNull(app, "app不存在");
  767 + Assert.notNull(stream, "stream不存在");
  768 + Assert.notNull(startTime, "startTime不存在");
  769 + Assert.notNull(endTime, "endTime不存在");
  770 + Assert.notEmpty(mediaServerItems, "流媒体列表为空");
  771 +
  772 + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
  773 + for (int i = 0; i < mediaServerItems.size(); i++) {
  774 + completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i));
  775 + }
  776 + List<RecordFile> result = new ArrayList<>();
  777 + for (int i = 0; i < completableFutures.length; i++) {
  778 + try {
  779 + List<RecordFile> list = (List<RecordFile>) completableFutures[i].get();
  780 + if (!list.isEmpty()) {
  781 + for (int g = 0; g < list.size(); g++) {
  782 + list.get(g).setMediaServerId(mediaServerItems.get(i).getId());
  783 + }
  784 + result.addAll(list);
  785 + }
  786 + } catch (InterruptedException e) {
  787 + throw new RuntimeException(e);
  788 + } catch (ExecutionException e) {
  789 + throw new RuntimeException(e);
  790 + }
  791 + }
  792 + Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName);
  793 + result.sort(comparator);
  794 + return result;
  795 + }
  796 +
  797 + @Override
  798 + public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) {
  799 + Assert.notNull(app, "app不存在");
  800 + Assert.notNull(stream, "stream不存在");
  801 + Assert.notEmpty(mediaServerItems, "流媒体列表为空");
  802 + CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()];
  803 +
  804 + for (int i = 0; i < mediaServerItems.size(); i++) {
  805 + completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i));
  806 + }
  807 + List<String> result = new ArrayList<>();
  808 + CompletableFuture.allOf(completableFutures).join();
  809 + for (CompletableFuture completableFuture : completableFutures) {
  810 + try {
  811 + List<String> list = (List<String>) completableFuture.get();
  812 + result.addAll(list);
  813 + } catch (InterruptedException e) {
  814 + throw new RuntimeException(e);
  815 + } catch (ExecutionException e) {
  816 + throw new RuntimeException(e);
  817 + }
  818 + }
  819 + Collections.sort(result);
  820 + return result;
  821 + }
  822 +
  823 + @Async
  824 + public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) {
  825 + JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month);
  826 + if (fileListJson != null && !fileListJson.isEmpty()) {
  827 + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
  828 + JSONArray data = fileListJson.getJSONArray("data");
  829 + return CompletableFuture.completedFuture(data.toJavaList(String.class));
  830 + }
  831 + }
  832 + return CompletableFuture.completedFuture(new ArrayList<>());
  833 + }
  834 +
  835 + @Async
  836 + public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) {
  837 + JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime);
  838 + if (fileListJson != null && !fileListJson.isEmpty()) {
  839 + if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) {
  840 + JSONObject data = fileListJson.getJSONObject("data");
  841 + JSONArray list = data.getJSONArray("list");
  842 + if (list != null) {
  843 + return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class));
  844 + }
  845 + }
  846 + }
  847 + return CompletableFuture.completedFuture(new ArrayList<>());
  848 + }
752 } 849 }
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
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
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
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 package com.genersoft.iot.vmp.utils; 1 package com.genersoft.iot.vmp.utils;
2 2
3 3
  4 +import org.apache.commons.lang3.ObjectUtils;
  5 +
4 import java.time.Instant; 6 import java.time.Instant;
5 import java.time.LocalDate; 7 import java.time.LocalDate;
6 import java.time.LocalDateTime; 8 import java.time.LocalDateTime;
@@ -109,6 +111,9 @@ public class DateUtil { @@ -109,6 +111,9 @@ public class DateUtil {
109 } 111 }
110 112
111 public static long getDifferenceForNow(String keepaliveTime) { 113 public static long getDifferenceForNow(String keepaliveTime) {
  114 + if (ObjectUtils.isEmpty(keepaliveTime)) {
  115 + return 0;
  116 + }
112 Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime)); 117 Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime));
113 return ChronoUnit.MILLIS.between(beforeInstant, Instant.now()); 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 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 - 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 100644 → 100755
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,7 +61,7 @@ public class LogController {
61 query = null; 61 query = null;
62 } 62 }
63 63
64 - if (!userSetting.getLogInDatebase()) { 64 + if (!userSetting.getLogInDatabase()) {
65 logger.warn("自动记录日志功能已关闭,查询结果可能不完整。"); 65 logger.warn("自动记录日志功能已关闭,查询结果可能不完整。");
66 } 66 }
67 67
src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java 100644 → 100755
@@ -91,10 +91,10 @@ public class PsController { @@ -91,10 +91,10 @@ public class PsController {
91 if (isSend != null && isSend && callId == null) { 91 if (isSend != null && isSend && callId == null) {
92 throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); 92 throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空");
93 } 93 }
94 - int ssrcInt = 0; 94 + long ssrcInt = 0;
95 if (ssrc != null) { 95 if (ssrc != null) {
96 try { 96 try {
97 - ssrcInt = Integer.parseInt(ssrc); 97 + ssrcInt = Long.parseLong(ssrc);
98 }catch (NumberFormatException e) { 98 }catch (NumberFormatException e) {
99 throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); 99 throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误");
100 } 100 }
@@ -223,8 +223,6 @@ public class PsController { @@ -223,8 +223,6 @@ public class PsController {
223 String is_Udp = isUdp ? "1" : "0"; 223 String is_Udp = isUdp ? "1" : "0";
224 param.put("is_udp", is_Udp); 224 param.put("is_udp", is_Udp);
225 param.put("src_port", sendInfo.getSendLocalPort()); 225 param.put("src_port", sendInfo.getSendLocalPort());
226 - param.put("use_ps", "0");  
227 - param.put("only_audio", "1");  
228 226
229 227
230 Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream); 228 Boolean streamReady = zlmServerFactory.isStreamReady(mediaServerItem, app, stream);
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,10 +91,10 @@ public class RtpController {
91 if (isSend != null && isSend && callId == null) { 91 if (isSend != null && isSend && callId == null) {
92 throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空"); 92 throw new ControllerException(ErrorCode.ERROR100.getCode(),"isSend为true时,CallID不能为空");
93 } 93 }
94 - int ssrcInt = 0; 94 + long ssrcInt = 0;
95 if (ssrc != null) { 95 if (ssrc != null) {
96 try { 96 try {
97 - ssrcInt = Integer.parseInt(ssrc); 97 + ssrcInt = Long.parseLong(ssrc);
98 }catch (NumberFormatException e) { 98 }catch (NumberFormatException e) {
99 throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误"); 99 throw new ControllerException(ErrorCode.ERROR100.getCode(),"ssrc格式错误");
100 } 100 }
@@ -247,7 +247,6 @@ public class RtpController { @@ -247,7 +247,6 @@ public class RtpController {
247 String is_Udp = isUdp ? "1" : "0"; 247 String is_Udp = isUdp ? "1" : "0";
248 paramForAudio.put("is_udp", is_Udp); 248 paramForAudio.put("is_udp", is_Udp);
249 paramForAudio.put("src_port", sendInfo.getSendLocalPortForAudio()); 249 paramForAudio.put("src_port", sendInfo.getSendLocalPortForAudio());
250 - paramForAudio.put("use_ps", "0");  
251 paramForAudio.put("only_audio", "1"); 250 paramForAudio.put("only_audio", "1");
252 if (ptForAudio != null) { 251 if (ptForAudio != null) {
253 paramForAudio.put("pt", ptForAudio); 252 paramForAudio.put("pt", ptForAudio);
@@ -268,7 +267,6 @@ public class RtpController { @@ -268,7 +267,6 @@ public class RtpController {
268 String is_Udp = isUdp ? "1" : "0"; 267 String is_Udp = isUdp ? "1" : "0";
269 paramForVideo.put("is_udp", is_Udp); 268 paramForVideo.put("is_udp", is_Udp);
270 paramForVideo.put("src_port", sendInfo.getSendLocalPortForVideo()); 269 paramForVideo.put("src_port", sendInfo.getSendLocalPortForVideo());
271 - paramForVideo.put("use_ps", "0");  
272 paramForVideo.put("only_audio", "0"); 270 paramForVideo.put("only_audio", "0");
273 if (ptForVideo != null) { 271 if (ptForVideo != null) {
274 paramForVideo.put("pt", ptForVideo); 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
src/main/resources/all-application.yml
@@ -178,7 +178,7 @@ user-settings: @@ -178,7 +178,7 @@ user-settings:
178 # 国标是否录制 178 # 国标是否录制
179 record-sip: true 179 record-sip: true
180 # 是否将日志存储进数据库 180 # 是否将日志存储进数据库
181 - logInDatebase: true 181 + logInDatabase: true
182 # 使用推流状态作为推流通道状态 182 # 使用推流状态作为推流通道状态
183 use-pushing-as-status: true 183 use-pushing-as-status: true
184 # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启 184 # 使用来源请求ip作为streamIp,当且仅当你只有zlm节点它与wvp在一起的情况下开启
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,19 +47,17 @@
47 :total="total"> 47 :total="total">
48 </el-pagination> 48 </el-pagination>
49 </div> 49 </div>
50 - <cloud-record-detail ref="cloudRecordDetail" v-if="recordDetail" :recordFile="chooseRecord" :mediaServerId="mediaServerId" :mediaServerPath="mediaServerPath" ></cloud-record-detail>  
51 50
52 </div> 51 </div>
53 </template> 52 </template>
54 53
55 <script> 54 <script>
56 import uiHeader from '../layout/UiHeader.vue' 55 import uiHeader from '../layout/UiHeader.vue'
57 - import cloudRecordDetail from './CloudRecordDetail.vue'  
58 import MediaServer from './service/MediaServer' 56 import MediaServer from './service/MediaServer'
59 export default { 57 export default {
60 name: 'app', 58 name: 'app',
61 components: { 59 components: {
62 - uiHeader, cloudRecordDetail 60 + uiHeader
63 }, 61 },
64 data() { 62 data() {
65 return { 63 return {
@@ -178,7 +176,7 @@ @@ -178,7 +176,7 @@
178 // }).catch(function (error) { 176 // }).catch(function (error) {
179 // console.log(error); 177 // console.log(error);
180 // }); 178 // });
181 - 179 + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
182 }, 180 },
183 deleteRecord(){ 181 deleteRecord(){
184 // TODO 182 // TODO
web_src/src/components/CloudRecordDetail.vue 100644 → 100755
1 <template> 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 <el-aside width="260px"> 30 <el-aside width="260px">
5 <div class="record-list-box-box"> 31 <div class="record-list-box-box">
6 <div style="margin-top: 20px"> 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 </div> 36 </div>
10 <div class="record-list-box" :style="recordListStyle"> 37 <div class="record-list-box" :style="recordListStyle">
11 <ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" > 38 <ul v-if="detailFiles.length >0" class="infinite-list record-list" v-infinite-scroll="infiniteScroll" >
12 <li v-for="(item,index) in detailFiles" :key="index" class="infinite-list-item record-list-item" > 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 <i class="el-icon-video-camera" ></i> 41 <i class="el-icon-video-camera" ></i>
15 - {{ item.substring(0,17)}} 42 + {{ getFileShowName(item.fileName) }}
16 </el-tag> 43 </el-tag>
17 - <el-tag type="danger" v-if="choosedFile == item"> 44 + <el-tag type="danger" v-if="choosedFile === item.filename">
18 <i class="el-icon-video-camera" ></i> 45 <i class="el-icon-video-camera" ></i>
19 - {{ item.substring(0,17)}} 46 + {{ getFileShowName(item.fileName) }}
20 </el-tag> 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 </li> 51 </li>
23 </ul> 52 </ul>
24 </div> 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 </div> 55 </div>
27 56
28 57
29 </el-aside> 58 </el-aside>
30 - <el-main style="padding: 22px"> 59 + <el-main style="padding: 22px">
31 <div class="playBox" :style="playerStyle"> 60 <div class="playBox" :style="playerStyle">
32 <player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player> 61 <player ref="recordVideoPlayer" :videoUrl="videoUrl" :height="true" style="width: 100%" ></player>
33 </div> 62 </div>
@@ -48,8 +77,8 @@ @@ -48,8 +77,8 @@
48 </div> 77 </div>
49 </div> 78 </div>
50 79
51 - </el-main>  
52 - </el-container> 80 + </el-main>
  81 + </el-container>
53 <el-drawer 82 <el-drawer
54 title="录像下载" 83 title="录像下载"
55 :visible.sync="drawer" 84 :visible.sync="drawer"
@@ -76,7 +105,8 @@ @@ -76,7 +105,8 @@
76 <li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index"> 105 <li class="task-list-item" v-for="(item, index) in taskListEnded" :key="index">
77 <div class="task-list-item-box" style="height: 2rem;line-height: 2rem;"> 106 <div class="task-list-item-box" style="height: 2rem;line-height: 2rem;">
78 <span>{{ item.startTime.substr(10) }}-{{item.endTime.substr(10)}}</span> 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 </a> 110 </a>
81 </div> 111 </div>
82 </li> 112 </li>
@@ -113,11 +143,16 @@ @@ -113,11 +143,16 @@
113 components: { 143 components: {
114 uiHeader, player 144 uiHeader, player
115 }, 145 },
116 - props: ['recordFile', 'mediaServerId', 'dateFiles'], 146 + // props: [ 'mediaServerId',],
117 data() { 147 data() {
118 return { 148 return {
  149 + app: this.$route.params.app,
  150 + stream: this.$route.params.stream,
  151 + mediaServerId: this.$route.params.mediaServerId,
119 dateFilesObj: [], 152 dateFilesObj: [],
  153 + mediaServerList: [],
120 detailFiles: [], 154 detailFiles: [],
  155 + loading: false,
121 chooseDate: null, 156 chooseDate: null,
122 videoUrl: null, 157 videoUrl: null,
123 choosedFile: null, 158 choosedFile: null,
@@ -195,6 +230,9 @@ @@ -195,6 +230,9 @@
195 mounted() { 230 mounted() {
196 this.recordListStyle.height = this.winHeight + "px"; 231 this.recordListStyle.height = this.winHeight + "px";
197 this.playerStyle["height"] = this.winHeight + "px"; 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 this.getDateInYear(()=>{ 237 this.getDateInYear(()=>{
200 if (Object.values(this.dateFilesObj).length > 0){ 238 if (Object.values(this.dateFilesObj).length > 0){
@@ -216,7 +254,8 @@ @@ -216,7 +254,8 @@
216 let chooseFullDate = new Date(this.chooseDate +" " + this.timeFormat); 254 let chooseFullDate = new Date(this.chooseDate +" " + this.timeFormat);
217 if (chooseFullDate.getFullYear() !== this.queryDate.getFullYear() 255 if (chooseFullDate.getFullYear() !== this.queryDate.getFullYear()
218 || chooseFullDate.getMonth() !== this.queryDate.getMonth()){ 256 || chooseFullDate.getMonth() !== this.queryDate.getMonth()){
219 - // this.getDateInYear() 257 + this.queryDate = chooseFullDate;
  258 + this.getDateInYear()
220 } 259 }
221 this.queryRecordDetails(()=>{ 260 this.queryRecordDetails(()=>{
222 if (this.detailFiles.length > 0){ 261 if (this.detailFiles.length > 0){
@@ -242,48 +281,69 @@ @@ -242,48 +281,69 @@
242 } 281 }
243 }, 282 },
244 queryRecordDetails: function (callback){ 283 queryRecordDetails: function (callback){
245 - let that = this;  
246 - that.$axios({ 284 + this.$axios({
247 method: 'get', 285 method: 'get',
248 - url:`/record_proxy/${that.mediaServerId}/api/record/file/list`, 286 + url: `/api/cloud/record/list`,
249 params: { 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 if (res.data.code === 0) { 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 if (callback) callback(); 310 if (callback) callback();
264 - }).catch(function (error) { 311 + }).catch((error) => {
265 console.log(error); 312 console.log(error);
266 - that.loading = false; 313 + this.loading = false;
267 }); 314 });
268 }, 315 },
269 chooseFile(file){ 316 chooseFile(file){
270 - this.choosedFile = file;  
271 if (file == null) { 317 if (file == null) {
272 this.videoUrl = ""; 318 this.videoUrl = "";
  319 + this.choosedFile = "";
273 }else { 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 console.log(this.videoUrl) 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 let basePath = "" 342 let basePath = ""
283 if (axios.defaults.baseURL.startsWith("http")) { 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 }else { 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 return basePath; 348 return basePath;
289 }, 349 },
@@ -316,7 +376,7 @@ @@ -316,7 +376,7 @@
316 }, 376 },
317 getTimeForFile(file){ 377 getTimeForFile(file){
318 console.log(file) 378 console.log(file)
319 - let timeStr = file.substring(0,17); 379 + let timeStr = file.fileName.substring(0, 17);
320 if(timeStr.indexOf("~") > 0){ 380 if(timeStr.indexOf("~") > 0){
321 timeStr = timeStr.replaceAll("-",":") 381 timeStr = timeStr.replaceAll("-",":")
322 } 382 }
@@ -370,27 +430,30 @@ @@ -370,27 +430,30 @@
370 }); 430 });
371 }, 431 },
372 getDateInYear(callback){ 432 getDateInYear(callback){
373 - let that = this;  
374 - that.dateFilesObj = {}; 433 + this.dateFilesObj = {};
375 this.$axios({ 434 this.$axios({
376 method: 'get', 435 method: 'get',
377 - url:`/record_proxy/${that.mediaServerId}/api/record/date/list`, 436 + url: `/api/cloud/record/date/list`,
378 params: { 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 if (res.data.code === 0) { 446 if (res.data.code === 0) {
384 if (res.data.data.length > 0) { 447 if (res.data.data.length > 0) {
385 for (let i = 0; i < res.data.data.length; i++) { 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 if(callback)callback(); 455 if(callback)callback();
393 - }).catch(function (error) { 456 + }).catch((error) => {
394 console.log(error); 457 console.log(error);
395 }); 458 });
396 }, 459 },
@@ -414,8 +477,8 @@ @@ -414,8 +477,8 @@
414 }, 477 },
415 addTask(){ 478 addTask(){
416 this.showTaskBox = true; 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 this.taskTimeRange[0] = new Date(startTimeStr) 482 this.taskTimeRange[0] = new Date(startTimeStr)
420 this.taskTimeRange[1] = new Date(endTimeStr) 483 this.taskTimeRange[1] = new Date(endTimeStr)
421 }, 484 },
@@ -425,8 +488,8 @@ @@ -425,8 +488,8 @@
425 method: 'get', 488 method: 'get',
426 url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`, 489 url:`/record_proxy/${that.mediaServerId}/api/record/file/download/task/add`,
427 params: { 490 params: {
428 - app: that.recordFile.app,  
429 - stream: that.recordFile.stream, 491 + app: that.app,
  492 + stream: that.stream,
430 startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'), 493 startTime: moment(this.taskTimeRange[0]).format('YYYY-MM-DD HH:mm:ss'),
431 endTime: moment(this.taskTimeRange[1]).format('YYYY-MM-DD HH:mm:ss'), 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,6 +89,8 @@
89 <el-button size="medium" icon="el-icon-position" type="text" v-if="!!scope.row.gbId" 89 <el-button size="medium" icon="el-icon-position" type="text" v-if="!!scope.row.gbId"
90 @click="removeFromGB(scope.row)">移出国标 90 @click="removeFromGB(scope.row)">移出国标
91 </el-button> 91 </el-button>
  92 + <el-button size="medium" icon="el-icon-cloudy" type="text" @click="queryCloudRecords(scope.row)">云端录像
  93 + </el-button>
92 </template> 94 </template>
93 </el-table-column> 95 </el-table-column>
94 </el-table> 96 </el-table>
@@ -257,6 +259,10 @@ export default { @@ -257,6 +259,10 @@ export default {
257 console.error(error); 259 console.error(error);
258 }); 260 });
259 }, 261 },
  262 + queryCloudRecords: function (row) {
  263 +
  264 + this.$router.push(`/cloudRecordDetail/${row.app}/${row.stream}`)
  265 + },
260 importChannel: function () { 266 importChannel: function () {
261 this.$refs.importChannel.openDialog(() => { 267 this.$refs.importChannel.openDialog(() => {
262 268
web_src/src/components/StreamProxyList.vue 100644 → 100755
@@ -91,6 +91,8 @@ @@ -91,6 +91,8 @@
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> 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 <el-divider v-if="!scope.row.enable" direction="vertical"></el-divider> 92 <el-divider v-if="!scope.row.enable" direction="vertical"></el-divider>
93 <el-button size="medium" icon="el-icon-delete" type="text" style="color: #f56c6c" @click="deleteStreamProxy(scope.row)">删除</el-button> 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 </template> 96 </template>
95 </el-table-column> 97 </el-table-column>
96 </el-table> 98 </el-table>
@@ -243,6 +245,10 @@ @@ -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 deleteStreamProxy: function(row){ 252 deleteStreamProxy: function(row){
247 let that = this; 253 let that = this;
248 this.$confirm('确定删除此代理吗?', '提示', { 254 this.$confirm('确定删除此代理吗?', '提示', {
web_src/src/components/UserManager.vue 100644 → 100755
web_src/src/components/channelList.vue 100644 → 100755
@@ -105,6 +105,9 @@ @@ -105,6 +105,9 @@
105 <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider> 105 <el-divider v-if="scope.row.subCount > 0 || scope.row.parental === 1" direction="vertical"></el-divider>
106 <el-button size="medium" v-bind:disabled="device == null || device.online === 0" icon="el-icon-video-camera" type="text" @click="queryRecords(scope.row)">设备录像 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 </el-button> 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 </template> 111 </template>
109 </el-table-column> 112 </el-table-column>
110 </el-table> 113 </el-table>
@@ -283,6 +286,12 @@ export default { @@ -283,6 +286,12 @@ export default {
283 286
284 this.$router.push(`/gbRecordDetail/${deviceId}/${channelId}`) 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 stopDevicePush: function (itemData) { 295 stopDevicePush: function (itemData) {
287 var that = this; 296 var that = this;
288 this.$axios({ 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,6 +12,7 @@ import map from &#39;../components/map.vue&#39;
12 import login from '../components/Login.vue' 12 import login from '../components/Login.vue'
13 import parentPlatformList from '../components/ParentPlatformList.vue' 13 import parentPlatformList from '../components/ParentPlatformList.vue'
14 import cloudRecord from '../components/CloudRecord.vue' 14 import cloudRecord from '../components/CloudRecord.vue'
  15 +import cloudRecordDetail from '../components/CloudRecordDetail.vue'
15 import mediaServerManger from '../components/MediaServerManger.vue' 16 import mediaServerManger from '../components/MediaServerManger.vue'
16 import web from '../components/setting/Web.vue' 17 import web from '../components/setting/Web.vue'
17 import sip from '../components/setting/Sip.vue' 18 import sip from '../components/setting/Sip.vue'
@@ -86,6 +87,16 @@ export default new VueRouter({ @@ -86,6 +87,16 @@ export default new VueRouter({
86 component: cloudRecord, 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 path: '/mediaServerManger', 100 path: '/mediaServerManger',
90 name: 'mediaServerManger', 101 name: 'mediaServerManger',
91 component: mediaServerManger, 102 component: mediaServerManger,