Commit 34135cce5d59f6ad7653737dd035bb1d441e185f

Authored by panlinlin
2 parents a63ae08f 730a64be

Merge remote-tracking branch 'origin/master' into wvp-28181-2.0

# Conflicts:
#	README.md
#	src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
#	src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
#	src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
#	src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java
#	src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
#	src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
#	src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
#	src/main/resources/application-dev.yml
#	web_src/src/components/gb28181/devicePlayer.vue
Showing 43 changed files with 1440 additions and 2198 deletions

Too many changes to show.

To preserve performance only 43 of 49 files are displayed.

... ... @@ -13,13 +13,38 @@
13 13 <artifactId>wvp</artifactId>
14 14 <name>web video platform</name>
15 15  
  16 + <repositories>
  17 + <repository>
  18 + <id>nexus-aliyun</id>
  19 + <name>Nexus aliyun</name>
  20 + <url>https://maven.aliyun.com/repository/public</url>
  21 + <layout>default</layout>
  22 + <snapshots>
  23 + <enabled>false</enabled>
  24 + </snapshots>
  25 + <releases>
  26 + <enabled>true</enabled>
  27 + </releases>
  28 + </repository>
  29 + </repositories>
  30 + <pluginRepositories>
  31 + <pluginRepository>
  32 + <id>nexus-aliyun</id>
  33 + <name>Nexus aliyun</name>
  34 + <url>https://maven.aliyun.com/repository/public</url>
  35 + <snapshots>
  36 + <enabled>false</enabled>
  37 + </snapshots>
  38 + <releases>
  39 + <enabled>true</enabled>
  40 + </releases>
  41 + </pluginRepository>
  42 + </pluginRepositories>
  43 +
16 44 <properties>
17 45 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
18 46  
19 47 <!-- 依赖版本 -->
20   - <mapper.version>4.1.5</mapper.version>
21   - <mybatis.version>3.5.5</mybatis.version>
22   - <mybatis.spring.version>2.0.5</mybatis.spring.version>
23 48 <pagehelper.version>5.2.0</pagehelper.version>
24 49 <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory>
25 50 <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory>
... ... @@ -31,30 +56,16 @@
31 56 <dependencies>
32 57 <dependency>
33 58 <groupId>org.springframework.boot</groupId>
34   - <artifactId>spring-boot-starter-jdbc</artifactId>
35   - </dependency>
36   - <dependency>
37   - <groupId>org.springframework.boot</groupId>
38   - <artifactId>spring-boot-starter-tomcat</artifactId>
  59 + <artifactId>spring-boot-starter-data-redis</artifactId>
39 60 </dependency>
40 61 <dependency>
41 62 <groupId>org.springframework.boot</groupId>
42 63 <artifactId>spring-boot-starter-web</artifactId>
43 64 </dependency>
44 65 <dependency>
45   - <groupId>org.springframework</groupId>
46   - <artifactId>spring-context</artifactId>
47   - </dependency>
48   -
49   - <!-- redis -->
50   - <dependency>
51   - <groupId>org.springframework.data</groupId>
52   - <artifactId>spring-data-redis</artifactId>
53   - </dependency>
54   - <dependency>
55   - <groupId>redis.clients</groupId>
56   - <artifactId>jedis</artifactId>
57   - <version>3.3.0</version>
  66 + <groupId>org.mybatis.spring.boot</groupId>
  67 + <artifactId>mybatis-spring-boot-starter</artifactId>
  68 + <version>2.1.4</version>
58 69 </dependency>
59 70  
60 71 <!-- druid数据库连接池 -->
... ... @@ -71,36 +82,25 @@
71 82 <version>8.0.22</version>
72 83 </dependency>
73 84  
74   - <!--Mybatis -->
75   - <dependency>
76   - <groupId>org.mybatis</groupId>
77   - <artifactId>mybatis</artifactId>
78   - <version>${mybatis.version}</version>
79   - </dependency>
  85 + <!-- 添加sqlite-jdbc数据库驱动 -->
80 86 <dependency>
81   - <groupId>org.mybatis</groupId>
82   - <artifactId>mybatis-spring</artifactId>
83   - <version>${mybatis.spring.version}</version>
  87 + <groupId>org.xerial</groupId>
  88 + <artifactId>sqlite-jdbc</artifactId>
  89 + <version>3.32.3.2</version>
84 90 </dependency>
85 91  
86   - <!--分页插件 -->
  92 + <!--Mybatis分页插件 -->
87 93 <dependency>
88 94 <groupId>com.github.pagehelper</groupId>
89   - <artifactId>pagehelper</artifactId>
90   - <version>${pagehelper.version}</version>
  95 + <artifactId>pagehelper-spring-boot-starter</artifactId>
  96 + <version>1.2.10</version>
91 97 </dependency>
92 98  
93   - <!--通用Mapper -->
94   - <dependency>
95   - <groupId>tk.mybatis</groupId>
96   - <artifactId>mapper</artifactId>
97   - <version>${mapper.version}</version>
98   - </dependency>
99   - <dependency>
100   - <groupId>org.apache.commons</groupId>
101   - <artifactId>commons-lang3</artifactId>
102   - <version>3.11</version>
103   - </dependency>
  99 +<!-- <dependency>-->
  100 +<!-- <groupId>org.apache.commons</groupId>-->
  101 +<!-- <artifactId>commons-lang3</artifactId>-->
  102 +<!-- <version>3.11</version>-->
  103 +<!-- </dependency>-->
104 104  
105 105 <!--Swagger2 -->
106 106 <!--在线文档 -->
... ...
src/main/java/com/genersoft/iot/vmp/common/PageResult.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.common;
2   -
3   -
4   -import java.util.List;
5   -
6   -public class PageResult<T> {
7   -
8   - private int page;
9   - private int count;
10   - private int total;
11   -
12   - private List<T> data;
13   -
14   - public List<T> getData() {
15   - return data;
16   - }
17   -
18   - public int getPage() {
19   - return page;
20   - }
21   -
22   - public void setPage(int page) {
23   - this.page = page;
24   - }
25   -
26   - public int getCount() {
27   - return count;
28   - }
29   -
30   - public void setCount(int count) {
31   - this.count = count;
32   - }
33   -
34   - public int getTotal() {
35   - return total;
36   - }
37   -
38   - public void setTotal(int total) {
39   - this.total = total;
40   - }
41   -
42   - public void setData(List<T> data) {
43   - this.data = data;
44   - }
45   -}
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
... ... @@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSONArray;
4 4  
5 5 public class StreamInfo {
6 6  
7   - private String ssrc;
8 7 private String streamId;
9 8 private String deviceID;
10 9 private String cahnnelId;
... ... @@ -20,14 +19,6 @@ public class StreamInfo {
20 19 private String rtsp;
21 20 private JSONArray tracks;
22 21  
23   - public String getSsrc() {
24   - return ssrc;
25   - }
26   -
27   - public void setSsrc(String ssrc) {
28   - this.ssrc = ssrc;
29   - }
30   -
31 22 public String getDeviceID() {
32 23 return deviceID;
33 24 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/ApplicationCheckRunner.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf;
  2 +
  3 +import org.slf4j.Logger;
  4 +import org.slf4j.LoggerFactory;
  5 +import org.springframework.beans.factory.annotation.Value;
  6 +import org.springframework.boot.CommandLineRunner;
  7 +import org.springframework.core.annotation.Order;
  8 +import org.springframework.stereotype.Component;
  9 +
  10 +
  11 +/**
  12 + * 对配置文件进行校验
  13 + */
  14 +@Component
  15 +@Order(value=2)
  16 +public class ApplicationCheckRunner implements CommandLineRunner {
  17 +
  18 + private Logger logger = LoggerFactory.getLogger("ApplicationCheckRunner");
  19 +
  20 + @Value("${sip.ip}")
  21 + private String sipIp;
  22 +
  23 + @Value("${media.ip}")
  24 + private String mediaIp;
  25 +
  26 + @Value("${media.wanIp}")
  27 + private String mediaWanIp;
  28 +
  29 + @Value("${media.hookIp}")
  30 + private String mediaHookIp;
  31 +
  32 + @Value("${media.port}")
  33 + private int mediaPort;
  34 +
  35 + @Value("${media.secret}")
  36 + private String mediaSecret;
  37 +
  38 + @Value("${media.streamNoneReaderDelayMS}")
  39 + private String streamNoneReaderDelayMS;
  40 +
  41 + @Value("${sip.ip}")
  42 + private String sipIP;
  43 +
  44 + @Value("${server.port}")
  45 + private String serverPort;
  46 +
  47 + @Value("${media.autoConfig}")
  48 + private boolean autoConfig;
  49 +
  50 +
  51 + @Override
  52 + public void run(String... args) throws Exception {
  53 + if (sipIP.equals("localhost") || sipIP.equals("127.0.0.1")) {
  54 + logger.error("sip.ip不能使用 {} ,请使用类似192.168.1.44这样的来自网卡的IP!!!", sipIP );
  55 + System.exit(1);
  56 + }
  57 +
  58 + if (mediaIp.equals("localhost") || mediaIp.equals("127.0.0.1")) {
  59 + logger.warn("mediaIp.ip使用 {} ,将无法收到网络内其他设备的推流!!!", mediaIp );
  60 + }
  61 +
  62 + }
  63 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
... ... @@ -8,8 +8,10 @@ import java.util.concurrent.ThreadPoolExecutor;
8 8 import java.util.concurrent.TimeUnit;
9 9  
10 10 import javax.sip.*;
  11 +import javax.sip.header.CallIdHeader;
11 12 import javax.sip.message.Response;
12 13  
  14 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
13 15 import org.slf4j.Logger;
14 16 import org.slf4j.LoggerFactory;
15 17 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -34,6 +36,9 @@ public class SipLayer implements SipListener {
34 36 @Autowired
35 37 private SIPProcessorFactory processorFactory;
36 38  
  39 + @Autowired
  40 + private SipSubscribe sipSubscribe;
  41 +
37 42 private SipStack sipStack;
38 43  
39 44 private SipFactory sipFactory;
... ... @@ -133,17 +138,34 @@ public class SipLayer implements SipListener {
133 138 // TODO Auto-generated catch block
134 139 e.printStackTrace();
135 140 }
  141 + if (evt.getResponse() != null && sipSubscribe.getOkSubscribesSize() > 0 ) {
  142 + CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
  143 + if (callIdHeader != null) {
  144 + SipSubscribe.Event subscribe = sipSubscribe.getOkSubscribe(callIdHeader.getCallId());
  145 + if (subscribe != null) {
  146 + subscribe.response(evt);
  147 + }
  148 + }
  149 + }
136 150 // } else if (status == Response.TRYING) {
137 151 // trying不会回复
138 152 } else if ((status >= 100) && (status < 200)) {
139 153 // 增加其它无需回复的响应,如101、180等
140 154 } else {
141 155 logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/);
  156 + if (evt.getResponse() != null && sipSubscribe.getErrorSubscribesSize() > 0 ) {
  157 + CallIdHeader callIdHeader = (CallIdHeader)evt.getResponse().getHeader(CallIdHeader.NAME);
  158 + if (callIdHeader != null) {
  159 + SipSubscribe.Event subscribe = sipSubscribe.getErrorSubscribe(callIdHeader.getCallId());
  160 + if (subscribe != null) {
  161 + subscribe.response(evt);
  162 + }
  163 + }
  164 + }
142 165 }
143   - // trying不会回复
144   - // if (status == Response.TRYING) {
145 166  
146   - // }
  167 +
  168 +
147 169 }
148 170  
149 171 /**
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
... ... @@ -27,6 +27,7 @@ package com.genersoft.iot.vmp.gb28181.auth;
27 27  
28 28 import java.security.MessageDigest;
29 29 import java.security.NoSuchAlgorithmException;
  30 +import java.text.DecimalFormat;
30 31 import java.util.Date;
31 32 import java.util.Random;
32 33  
... ... @@ -103,9 +104,12 @@ public class DigestServerAuthenticationHelper {
103 104 .createWWWAuthenticateHeader(DEFAULT_SCHEME);
104 105 proxyAuthenticate.setParameter("realm", realm);
105 106 proxyAuthenticate.setParameter("nonce", generateNonce());
  107 +
106 108 proxyAuthenticate.setParameter("opaque", "");
107 109 proxyAuthenticate.setParameter("stale", "FALSE");
108 110 proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM);
  111 +
  112 +// proxyAuthenticate.setParameter("qop", "auth");
109 113 response.setHeader(proxyAuthenticate);
110 114 } catch (Exception ex) {
111 115 InternalErrorHandler.handleException(ex);
... ... @@ -170,42 +174,116 @@ public class DigestServerAuthenticationHelper {
170 174 public boolean doAuthenticatePlainTextPassword(Request request, String pass) {
171 175 AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
172 176 if ( authHeader == null ) return false;
173   - String realm = authHeader.getRealm();
174   - String username = authHeader.getUsername();
175   -
176   -
  177 + String realm = authHeader.getRealm().trim();
  178 + String username = authHeader.getUsername().trim();
  179 +
177 180 if ( username == null || realm == null ) {
178 181 return false;
179 182 }
180   -
181 183  
182 184 String nonce = authHeader.getNonce();
183 185 URI uri = authHeader.getURI();
184 186 if (uri == null) {
185 187 return false;
186 188 }
187   -
  189 + // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
  190 + String qop = authHeader.getQop();
  191 +
  192 + // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
  193 + // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
  194 + String cNonce = authHeader.getCNonce();
  195 +
  196 + // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量
  197 + int nc = authHeader.getNonceCount();
  198 + String ncStr = new DecimalFormat("00000000").format(nc);
  199 +// String ncStr = new DecimalFormat("00000000").format(Integer.parseInt(nc + "", 16));
188 200  
189 201 String A1 = username + ":" + realm + ":" + pass;
190 202 String A2 = request.getMethod().toUpperCase() + ":" + uri.toString();
191 203 byte mdbytes[] = messageDigest.digest(A1.getBytes());
192 204 String HA1 = toHexString(mdbytes);
  205 + System.out.println("A1: " + A1);
  206 + System.out.println("A2: " + A2);
193 207  
194   -
195 208 mdbytes = messageDigest.digest(A2.getBytes());
196 209 String HA2 = toHexString(mdbytes);
197   -
  210 + System.out.println("HA1: " + HA1);
  211 + System.out.println("HA2: " + HA2);
198 212 String cnonce = authHeader.getCNonce();
  213 + System.out.println("nonce: " + nonce);
  214 + System.out.println("nc: " + ncStr);
  215 + System.out.println("cnonce: " + cnonce);
  216 + System.out.println("qop: " + qop);
199 217 String KD = HA1 + ":" + nonce;
200   - if (cnonce != null) {
201   - KD += ":" + cnonce;
  218 +
  219 + if (qop != null && qop.equals("auth") ) {
  220 + if (nc != -1) {
  221 + KD += ":" + ncStr;
  222 + }
  223 + if (cnonce != null) {
  224 + KD += ":" + cnonce;
  225 + }
  226 + KD += ":" + qop;
202 227 }
203 228 KD += ":" + HA2;
  229 + System.out.println("KD: " + KD);
204 230 mdbytes = messageDigest.digest(KD.getBytes());
205 231 String mdString = toHexString(mdbytes);
  232 + System.out.println("mdString: " + mdString);
206 233 String response = authHeader.getResponse();
  234 + System.out.println("response: " + response);
207 235 return mdString.equals(response);
208 236  
209 237 }
210 238  
  239 +
  240 + public static void main(String[] args) throws NoSuchAlgorithmException {
  241 + MessageDigest messageDigest2 = MessageDigest.getInstance(DEFAULT_ALGORITHM);
  242 + String realm = "DS-2CD2520F";
  243 + String username = "admin";
  244 + String passwd = "12345";
  245 +
  246 + String nonce = "4d6a553452444d30525441364e6d4d304e6a68684e47553d";
  247 +
  248 + String uri = "/ISAPI/Streaming/channels/101/picture";
  249 + // qop 保护质量 包含auth(默认的)和auth-int(增加了报文完整性检测)两种策略
  250 + String qop = "auth";
  251 +
  252 + // 客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。
  253 + // 这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
  254 + String cNonce = "C1A5298F939E87E8F962A5EDFC206918";
  255 +
  256 + // nonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量
  257 + int nc = 1;
  258 +
  259 + String A1 = username + ":" + realm + ":" + passwd;
  260 + System.out.println("A1: " + A1);
  261 + String A2 = "GET" + ":" + uri.toString();
  262 + System.out.println("A2: " + A2);
  263 + byte mdbytes[] = messageDigest2.digest(A1.getBytes());
  264 + String HA1 = toHexString(mdbytes);
  265 + System.out.println("HA1: " + HA1);
  266 +
  267 + mdbytes = messageDigest2.digest(A2.getBytes());
  268 + String HA2 = toHexString(mdbytes);
  269 + System.out.println("HA2: " + HA2);
  270 + String cnonce = "93d4d37df32e1a85";
  271 + String KD = HA1 + ":" + nonce;
  272 +
  273 + if (nc != -1) {
  274 + KD += ":" + "00000001";
  275 + }
  276 + if (cnonce != null) {
  277 + KD += ":" + cnonce;
  278 + }
  279 + if (qop != null) {
  280 + KD += ":" + qop;
  281 + }
  282 + KD += ":" + HA2;
  283 + System.out.println("KD: " + KD);
  284 + mdbytes = messageDigest2.digest(KD.getBytes());
  285 + String mdString = toHexString(mdbytes);
  286 + String response = "3993a815e5cdaf4470e9b4f9bd41cf4a";
  287 + System.out.println(mdString);
  288 + }
211 289 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/auth/RegisterLogicHandler.java
... ... @@ -21,6 +21,6 @@ public class RegisterLogicHandler {
21 21 // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口
22 22 cmder.deviceInfoQuery(device);
23 23  
24   - cmder.catalogQuery(device);
  24 + cmder.catalogQuery(device, null);
25 25 }
26 26 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
1 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3  
4   -import java.util.List;
5   -import java.util.Map;
6   -
7 4 public class Device {
8 5  
9 6 /**
... ... @@ -46,24 +43,36 @@ public class Device {
46 43 private String streamMode;
47 44  
48 45 /**
  46 + * wan地址_ip
  47 + */
  48 + private String ip;
  49 +
  50 + /**
  51 + * wan地址_port
  52 + */
  53 + private int port;
  54 +
  55 + /**
49 56 * wan地址
50 57 */
51   - private Host host;
  58 + private String hostAddress;
52 59  
53 60 /**
54 61 * 在线
55 62 */
56 63 private int online;
57 64  
  65 +
58 66 /**
59   - * 通道列表
  67 + * 注册时间
60 68 */
61   -// private Map<String,DeviceChannel> channelMap;
  69 + private Long registerTimeMillis;
62 70  
  71 + /**
  72 + * 通道个数
  73 + */
63 74 private int channelCount;
64 75  
65   - private List<String> channelList;
66   -
67 76 public String getDeviceId() {
68 77 return deviceId;
69 78 }
... ... @@ -120,12 +129,28 @@ public class Device {
120 129 this.streamMode = streamMode;
121 130 }
122 131  
123   - public Host getHost() {
124   - return host;
  132 + public String getIp() {
  133 + return ip;
  134 + }
  135 +
  136 + public void setIp(String ip) {
  137 + this.ip = ip;
  138 + }
  139 +
  140 + public int getPort() {
  141 + return port;
  142 + }
  143 +
  144 + public void setPort(int port) {
  145 + this.port = port;
  146 + }
  147 +
  148 + public String getHostAddress() {
  149 + return hostAddress;
125 150 }
126 151  
127   - public void setHost(Host host) {
128   - this.host = host;
  152 + public void setHostAddress(String hostAddress) {
  153 + this.hostAddress = hostAddress;
129 154 }
130 155  
131 156 public int getOnline() {
... ... @@ -144,11 +169,11 @@ public class Device {
144 169 this.channelCount = channelCount;
145 170 }
146 171  
147   - public List<String> getChannelList() {
148   - return channelList;
  172 + public Long getRegisterTimeMillis() {
  173 + return registerTimeMillis;
149 174 }
150 175  
151   - public void setChannelList(List<String> channelList) {
152   - this.channelList = channelList;
  176 + public void setRegisterTimeMillis(Long registerTimeMillis) {
  177 + this.registerTimeMillis = registerTimeMillis;
153 178 }
154 179 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java
... ... @@ -2,10 +2,17 @@ package com.genersoft.iot.vmp.gb28181.bean;
2 2  
3 3 public class DeviceChannel {
4 4  
  5 +
  6 +
5 7 /**
6 8 * 通道id
7 9 */
8 10 private String channelId;
  11 +
  12 + /**
  13 + * 设备id
  14 + */
  15 + private String deviceId;
9 16  
10 17 /**
11 18 * 通道名
... ... @@ -141,18 +148,20 @@ public class DeviceChannel {
141 148 /**
142 149 * 流唯一编号,存在表示正在直播
143 150 */
144   - private String ssrc;
  151 + private String streamId;
145 152  
146 153 /**
147 154 * 是否含有音频
148 155 */
149   - private boolean hasAudio;
  156 + private boolean hasAudio;
150 157  
151   - /**
152   - * 是否正在播放
153   - */
154   - private boolean play;
  158 + public String getDeviceId() {
  159 + return deviceId;
  160 + }
155 161  
  162 + public void setDeviceId(String deviceId) {
  163 + this.deviceId = deviceId;
  164 + }
156 165  
157 166 public void setPTZType(int PTZType) {
158 167 this.PTZType = PTZType;
... ... @@ -379,14 +388,6 @@ public class DeviceChannel {
379 388 this.subCount = subCount;
380 389 }
381 390  
382   - public String getSsrc() {
383   - return ssrc;
384   - }
385   -
386   - public void setSsrc(String ssrc) {
387   - this.ssrc = ssrc;
388   - }
389   -
390 391 public boolean isHasAudio() {
391 392 return hasAudio;
392 393 }
... ... @@ -395,11 +396,11 @@ public class DeviceChannel {
395 396 this.hasAudio = hasAudio;
396 397 }
397 398  
398   - public boolean isPlay() {
399   - return play;
  399 + public String getStreamId() {
  400 + return streamId;
400 401 }
401 402  
402   - public void setPlay(boolean play) {
403   - this.play = play;
  403 + public void setStreamId(String streamId) {
  404 + this.streamId = streamId;
404 405 }
405 406 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.event;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
  5 +import org.slf4j.Logger;
  6 +import org.slf4j.LoggerFactory;
  7 +import org.springframework.stereotype.Component;
  8 +
  9 +import javax.sip.ResponseEvent;
  10 +import javax.sip.message.Request;
  11 +import java.util.EventObject;
  12 +import java.util.Map;
  13 +import java.util.concurrent.ConcurrentHashMap;
  14 +
  15 +@Component
  16 +public class SipSubscribe {
  17 +
  18 + private final static Logger logger = LoggerFactory.getLogger(SipSubscribe.class);
  19 +
  20 + private Map<String, SipSubscribe.Event> errorSubscribes = new ConcurrentHashMap<>();
  21 +
  22 + private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
  23 +
  24 + public interface Event {
  25 + void response(ResponseEvent event);
  26 + }
  27 +
  28 + public void addErrorSubscribe(String key, SipSubscribe.Event event) {
  29 + errorSubscribes.put(key, event);
  30 + }
  31 +
  32 + public void addOkSubscribe(String key, SipSubscribe.Event event) {
  33 + okSubscribes.put(key, event);
  34 + }
  35 +
  36 + public SipSubscribe.Event getErrorSubscribe(String key) {
  37 + return errorSubscribes.get(key);
  38 + }
  39 +
  40 + public SipSubscribe.Event getOkSubscribe(String key) {
  41 + return okSubscribes.get(key);
  42 + }
  43 +
  44 + public int getErrorSubscribesSize(){
  45 + return errorSubscribes.size();
  46 + }
  47 + public int getOkSubscribesSize(){
  48 + return okSubscribes.size();
  49 + }
  50 +}
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorFactory.java
... ... @@ -7,8 +7,10 @@ import javax.sip.header.CSeqHeader;
7 7 import javax.sip.message.Request;
8 8 import javax.sip.message.Response;
9 9  
  10 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 11 import com.alibaba.fastjson.JSON;
11 12 import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
  13 +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*;
12 14 import org.slf4j.Logger;
13 15 import org.slf4j.LoggerFactory;
14 16 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -54,7 +56,10 @@ public class SIPProcessorFactory {
54 56  
55 57 @Autowired
56 58 private IVideoManagerStorager storager;
57   -
  59 +
  60 + @Autowired
  61 + private IRedisCatchStorage redisCatchStorage;
  62 +
58 63 @Autowired
59 64 private EventPublisher publisher;
60 65  
... ... @@ -82,10 +87,11 @@ public class SIPProcessorFactory {
82 87 @Autowired
83 88 @Lazy
84 89 private RegisterResponseProcessor registerResponseProcessor;
85   -
  90 +
86 91 @Autowired
87 92 private OtherResponseProcessor otherResponseProcessor;
88   -
  93 +
  94 +
89 95 // 注:这里使用注解会导致循环依赖注入,暂用springBean
90 96 private SipProvider tcpSipProvider;
91 97  
... ... @@ -140,6 +146,7 @@ public class SIPProcessorFactory {
140 146 processor.setOffLineDetector(offLineDetector);
141 147 processor.setCmder(cmder);
142 148 processor.setStorager(storager);
  149 + processor.setRedisCatchStorage(redisCatchStorage);
143 150 return processor;
144 151 } else {
145 152 return new OtherRequestProcessor();
... ... @@ -147,6 +154,7 @@ public class SIPProcessorFactory {
147 154 }
148 155  
149 156 public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) {
  157 +
150 158 Response response = evt.getResponse();
151 159 CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
152 160 String method = cseqHeader.getMethod();
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.callback;
2 2  
3 3 import java.util.HashMap;
4 4 import java.util.Map;
  5 +import java.util.concurrent.ConcurrentHashMap;
5 6  
6 7 import org.springframework.http.HttpStatus;
7 8 import org.springframework.http.ResponseEntity;
... ... @@ -24,8 +25,10 @@ public class DeferredResultHolder {
24 25  
25 26 public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY";
26 27  
27   - private Map<String, DeferredResult> map = new HashMap<String, DeferredResult>();
28   -
  28 + public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP";
  29 +
  30 + private Map<String, DeferredResult> map = new ConcurrentHashMap<String, DeferredResult>();
  31 +
29 32 public void put(String key, DeferredResult result) {
30 33 map.put(key, result);
31 34 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java
... ... @@ -2,8 +2,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd;
2 2  
3 3 import com.genersoft.iot.vmp.common.StreamInfo;
4 4 import com.genersoft.iot.vmp.gb28181.bean.Device;
  5 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
5 6 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
6   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
7 7  
8 8 /**
9 9 * @Description:设备能力接口,用于定义设备的控制、查询能力
... ... @@ -84,7 +84,7 @@ public interface ISIPCommander {
84 84 * @param device 视频设备
85 85 * @param channelId 预览通道
86 86 */
87   - void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event);
  87 + void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
88 88  
89 89 /**
90 90 * 请求回放视频流
... ... @@ -94,15 +94,16 @@ public interface ISIPCommander {
94 94 * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss
95 95 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
96 96 */
97   - void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event);
  97 + void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent);
98 98  
99 99 /**
100 100 * 视频流停止
101 101 *
102 102 * @param ssrc ssrc
103 103 */
  104 + void streamByeCmd(String ssrc, SipSubscribe.Event okEvent);
104 105 void streamByeCmd(String ssrc);
105   -
  106 +
106 107 /**
107 108 * 语音广播
108 109 *
... ... @@ -176,7 +177,7 @@ public interface ISIPCommander {
176 177 *
177 178 * @param device 视频设备
178 179 */
179   - boolean catalogQuery(Device device);
  180 + boolean catalogQuery(Device device, SipSubscribe.Event errorEvent);
180 181  
181 182 /**
182 183 * 查询录像信息
... ... @@ -214,4 +215,11 @@ public interface ISIPCommander {
214 215 * @param device 视频设备
215 216 */
216 217 boolean mobilePostitionQuery(Device device);
  218 +
  219 + /**
  220 + * 释放rtpserver
  221 + * @param device
  222 + * @param channelId
  223 + */
  224 + void closeRTPServer(Device device, String channelId);
217 225 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
... ... @@ -47,9 +47,8 @@ public class SIPRequestHeaderProvider {
47 47  
48 48 public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
49 49 Request request = null;
50   - Host host = device.getHost();
51 50 // sipuri
52   - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
  51 + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
53 52 // via
54 53 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
55 54 ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(),
... ... @@ -75,22 +74,21 @@ public class SIPRequestHeaderProvider {
75 74  
76 75 request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader,
77 76 toHeader, viaHeaders, maxForwards);
78   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml");
  77 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml");
79 78 request.setContent(content, contentTypeHeader);
80 79 return request;
81 80 }
82 81  
83 82 public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
84 83 Request request = null;
85   - Host host = device.getHost();
86 84 //请求行
87   - SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, host.getAddress());
  85 + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(channelId, device.getHostAddress());
88 86 //via
89 87 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
90   - // ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
91   - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag);
  88 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
92 89 viaHeader.setRPort();
93 90 viaHeaders.add(viaHeader);
  91 +
94 92 //from
95 93 SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain());
96 94 Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI);
... ... @@ -122,20 +120,18 @@ public class SIPRequestHeaderProvider {
122 120 // Subject
123 121 SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0));
124 122 request.addHeader(subjectHeader);
125   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP");
  123 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
126 124 request.setContent(content, contentTypeHeader);
127 125 return request;
128 126 }
129 127  
130 128 public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException {
131 129 Request request = null;
132   - Host host = device.getHost();
133 130 //请求行
134   - SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress());
135   - //via
  131 + SipURI requestLine = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
  132 + // via
136 133 ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
137   - // ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), device.getTransport(), viaTag);
138   - ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getHost().getIp(), device.getHost().getPort(), device.getTransport(), viaTag);
  134 + ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(device.getIp(), device.getPort(), device.getTransport(), viaTag);
139 135 viaHeader.setRPort();
140 136 viaHeaders.add(viaHeader);
141 137 //from
... ... @@ -167,7 +163,7 @@ public class SIPRequestHeaderProvider {
167 163 // Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort()));
168 164 request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress));
169 165  
170   - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP");
  166 + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
171 167 request.setContent(content, contentTypeHeader);
172 168 return request;
173 169 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
1 1 package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl;
2 2  
3 3 import java.text.ParseException;
  4 +import java.util.UUID;
4 5 import java.util.regex.Matcher;
5 6 import java.util.regex.Pattern;
6 7  
7   -import javax.sip.ClientTransaction;
8   -import javax.sip.Dialog;
9   -import javax.sip.InvalidArgumentException;
10   -import javax.sip.SipException;
11   -import javax.sip.SipFactory;
12   -import javax.sip.SipProvider;
13   -import javax.sip.TransactionDoesNotExistException;
  8 +import javax.sip.*;
14 9 import javax.sip.address.SipURI;
  10 +import javax.sip.header.CallIdHeader;
  11 +import javax.sip.header.Header;
15 12 import javax.sip.header.ViaHeader;
16 13 import javax.sip.message.Request;
17 14  
... ... @@ -19,9 +16,13 @@ import com.alibaba.fastjson.JSONObject;
19 16 import com.genersoft.iot.vmp.common.StreamInfo;
20 17 import com.genersoft.iot.vmp.conf.MediaServerConfig;
21 18 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  19 +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe;
22 20 import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe;
23   -import com.genersoft.iot.vmp.media.zlm.ZLMUtils;
  21 +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  22 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
24 23 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  24 +import org.slf4j.Logger;
  25 +import org.slf4j.LoggerFactory;
25 26 import org.springframework.beans.factory.annotation.Autowired;
26 27 import org.springframework.beans.factory.annotation.Qualifier;
27 28 import org.springframework.beans.factory.annotation.Value;
... ... @@ -41,6 +42,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil;
41 42 */
42 43 @Component
43 44 public class SIPCommander implements ISIPCommander {
  45 +
  46 + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class);
44 47  
45 48 @Autowired
46 49 private SipConfig sipConfig;
... ... @@ -53,6 +56,9 @@ public class SIPCommander implements ISIPCommander {
53 56  
54 57 @Autowired
55 58 private IVideoManagerStorager storager;
  59 +
  60 + @Autowired
  61 + private IRedisCatchStorage redisCatchStorage;
56 62  
57 63 @Autowired
58 64 @Qualifier(value="tcpSipProvider")
... ... @@ -63,14 +69,20 @@ public class SIPCommander implements ISIPCommander {
63 69 private SipProvider udpSipProvider;
64 70  
65 71 @Autowired
66   - private ZLMUtils zlmUtils;
  72 + private ZLMRTPServerFactory zlmrtpServerFactory;
67 73  
68 74 @Value("${media.rtp.enable}")
69 75 private boolean rtpEnable;
70 76  
  77 + @Value("${media.seniorSdp}")
  78 + private boolean seniorSdp;
  79 +
71 80 @Autowired
72 81 private ZLMHttpHookSubscribe subscribe;
73 82  
  83 + @Autowired
  84 + private SipSubscribe sipSubscribe;
  85 +
74 86  
75 87  
76 88 /**
... ... @@ -176,19 +188,29 @@ public class SIPCommander implements ISIPCommander {
176 188 * @param moveSpeed 镜头移动速度 默认 0XFF (0-255)
177 189 * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255)
178 190 */
179   - public static String frontEndCmdString(int cmdCode, int parameter1, int parameter2, int combineCode2) {
  191 +
  192 + /**
  193 + * 云台指令码计算
  194 + *
  195 + * @param cmdCode 指令码
  196 + * @param horizonSpeed 水平移动速度
  197 + * @param verticalSpeed 垂直移动速度
  198 + * @param zoomSpeed 缩放速度
  199 + * @return
  200 + */
  201 + public static String frontEndCmdString(int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) {
180 202 StringBuilder builder = new StringBuilder("A50F01");
181 203 String strTmp;
182 204 strTmp = String.format("%02X", cmdCode);
183 205 builder.append(strTmp, 0, 2);
184   - strTmp = String.format("%02X", parameter1);
  206 + strTmp = String.format("%02X", horizonSpeed);
185 207 builder.append(strTmp, 0, 2);
186   - strTmp = String.format("%02X", parameter2);
  208 + strTmp = String.format("%02X", verticalSpeed);
187 209 builder.append(strTmp, 0, 2);
188   - strTmp = String.format("%X", combineCode2);
  210 + strTmp = String.format("%X", zoomSpeed);
189 211 builder.append(strTmp, 0, 1).append("0");
190 212 //计算校验码
191   - int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + parameter1 + parameter2 + (combineCode2 & 0XF0)) % 0X100;
  213 + int checkCode = (0XA5 + 0X0F + 0X01 + cmdCode + horizonSpeed + verticalSpeed + (zoomSpeed & 0XF0)) % 0X100;
192 214 strTmp = String.format("%02X", checkCode);
193 215 builder.append(strTmp, 0, 2);
194 216 return builder.toString();
... ... @@ -237,14 +259,14 @@ public class SIPCommander implements ISIPCommander {
237 259 * @param device 控制设备
238 260 * @param channelId 预览通道
239 261 * @param cmdCode 指令码
240   - * @param parameter1 数据1
241   - * @param parameter2 数据2
242   - * @param combineCode2 组合码2
  262 + * @param horizonSpeed 水平移动速度
  263 + * @param verticalSpeed 垂直移动速度
  264 + * @param zoomSpeed 缩放速度
243 265 */
244 266 @Override
245   - public boolean frontEndCmd(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combineCode2) {
  267 + public boolean frontEndCmd(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) {
246 268 try {
247   - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2);
  269 + String cmdStr= frontEndCmdString(cmdCode, horizonSpeed, verticalSpeed, zoomSpeed);
248 270 System.out.println("控制字符串:" + cmdStr);
249 271 StringBuffer ptzXml = new StringBuffer(200);
250 272 ptzXml.append("<?xml version=\"1.0\" ?>\r\n");
... ... @@ -258,7 +280,6 @@ public class SIPCommander implements ISIPCommander {
258 280 ptzXml.append("</Control>\r\n");
259 281  
260 282 Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag");
261   -
262 283 transmitRequest(device, request);
263 284 return true;
264 285 } catch (SipException | ParseException | InvalidArgumentException e) {
... ... @@ -266,28 +287,39 @@ public class SIPCommander implements ISIPCommander {
266 287 }
267 288 return false;
268 289 }
  290 +
269 291 /**
270   - * 请求预览视频流
271   - *
  292 + * 请求预览视频流
272 293 * @param device 视频设备
273 294 * @param channelId 预览通道
  295 + * @param event hook订阅
  296 + * @param errorEvent sip错误订阅
274 297 */
275 298 @Override
276   - public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event) {
  299 + public void playStreamCmd(Device device, String channelId, ZLMHttpHookSubscribe.Event event, SipSubscribe.Event errorEvent) {
277 300 try {
278 301  
279 302 String ssrc = streamSession.createPlaySsrc();
  303 + String streamId = null;
  304 + if (rtpEnable) {
  305 + streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
  306 + }else {
  307 + streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  308 + }
280 309 String streamMode = device.getStreamMode().toUpperCase();
281   - MediaServerConfig mediaInfo = storager.getMediaInfo();
  310 + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
  311 + if (mediaInfo == null) {
  312 + logger.warn("点播时发现ZLM尚未连接...");
  313 + return;
  314 + }
282 315 String mediaPort = null;
283 316 // 使用动态udp端口
284 317 if (rtpEnable) {
285   - mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
  318 + mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
286 319 }else {
287 320 mediaPort = mediaInfo.getRtpProxyPort();
288 321 }
289 322  
290   - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
291 323 // 添加订阅
292 324 JSONObject subscribeKey = new JSONObject();
293 325 subscribeKey.put("app", "rtp");
... ... @@ -297,7 +329,8 @@ public class SIPCommander implements ISIPCommander {
297 329 //
298 330 StringBuffer content = new StringBuffer(200);
299 331 content.append("v=0\r\n");
300   - content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
  332 +// content.append("o="+channelId+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
  333 + content.append("o="+"00000"+" 0 0 IN IP4 "+mediaInfo.getWanIp()+"\r\n");
301 334 content.append("s=Play\r\n");
302 335 content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n");
303 336 content.append("t=0 0\r\n");
... ... @@ -327,17 +360,14 @@ public class SIPCommander implements ISIPCommander {
327 360 }
328 361 content.append("y="+ssrc+"\r\n");//ssrc
329 362  
  363 +// String fromTag = UUID.randomUUID().toString();
  364 +// Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, fromTag, null, ssrc);
  365 +
330 366 Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc);
331 367  
332   - ClientTransaction transaction = transmitRequest(device, request);
333   - streamSession.put(ssrc, transaction);
334   - DeviceChannel deviceChannel = storager.queryChannel(device.getDeviceId(), channelId);
335   - if (deviceChannel != null) {
336   - deviceChannel.setSsrc(ssrc);
337   - storager.updateChannel(device.getDeviceId(), deviceChannel);
338   - }
  368 + ClientTransaction transaction = transmitRequest(device, request, errorEvent);
  369 + streamSession.put(streamId, transaction);
339 370  
340   - // TODO 订阅SIP response,处理对方的错误返回
341 371  
342 372  
343 373 } catch ( SipException | ParseException | InvalidArgumentException e) {
... ... @@ -354,9 +384,10 @@ public class SIPCommander implements ISIPCommander {
354 384 * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss
355 385 */
356 386 @Override
357   - public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event) {
  387 + public void playbackStreamCmd(Device device, String channelId, String startTime, String endTime, ZLMHttpHookSubscribe.Event event
  388 + , SipSubscribe.Event errorEvent) {
358 389 try {
359   - MediaServerConfig mediaInfo = storager.getMediaInfo();
  390 + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
360 391 String ssrc = streamSession.createPlayBackSsrc();
361 392 String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
362 393 // 添加订阅
... ... @@ -378,57 +409,91 @@ public class SIPCommander implements ISIPCommander {
378 409 String mediaPort = null;
379 410 // 使用动态udp端口
380 411 if (rtpEnable) {
381   - mediaPort = zlmUtils.getNewRTPPort(ssrc) + "";
  412 + mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + "";
382 413 }else {
383 414 mediaPort = mediaInfo.getRtpProxyPort();
384 415 }
385 416 String streamMode = device.getStreamMode().toUpperCase();
386   - if("TCP-PASSIVE".equals(streamMode)) {
387   - content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
388   - }else if ("TCP-ACTIVE".equals(streamMode)) {
389   - content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
390   - }else if("UDP".equals(streamMode)) {
391   - content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
392   - }
393   - content.append("a=recvonly\r\n");
394   - content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
395   - content.append("a=rtpmap:126 H264/90000\r\n");
396   - content.append("a=rtpmap:125 H264S/90000\r\n");
397   - content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
398   - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
399   - content.append("a=fmtp:99 profile-level-id=3\r\n");
400   - content.append("a=rtpmap:98 H264/90000\r\n");
401   - content.append("a=rtpmap:97 MPEG4/90000\r\n");
402   - content.append("a=rtpmap:96 PS/90000\r\n");
403   - if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
404   - content.append("a=setup:passive\r\n");
405   - content.append("a=connection:new\r\n");
406   - }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
407   - content.append("a=setup:active\r\n");
408   - content.append("a=connection:new\r\n");
  417 +
  418 + if (seniorSdp) {
  419 + if("TCP-PASSIVE".equals(streamMode)) {
  420 + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
  421 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  422 + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 126 125 99 34 98 97 96\r\n");
  423 + }else if("UDP".equals(streamMode)) {
  424 + content.append("m=video "+ mediaPort +" RTP/AVP 126 125 99 34 98 97 96\r\n");
  425 + }
  426 + content.append("a=recvonly\r\n");
  427 + content.append("a=fmtp:126 profile-level-id=42e01e\r\n");
  428 + content.append("a=rtpmap:126 H264/90000\r\n");
  429 + content.append("a=rtpmap:125 H264S/90000\r\n");
  430 + content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
  431 + content.append("a=rtpmap:99 MP4V-ES/90000\r\n");
  432 + content.append("a=fmtp:99 profile-level-id=3\r\n");
  433 + content.append("a=rtpmap:98 H264/90000\r\n");
  434 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  435 + content.append("a=rtpmap:96 PS/90000\r\n");
  436 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  437 + content.append("a=setup:passive\r\n");
  438 + content.append("a=connection:new\r\n");
  439 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  440 + content.append("a=setup:active\r\n");
  441 + content.append("a=connection:new\r\n");
  442 + }
  443 + }else {
  444 + if("TCP-PASSIVE".equals(streamMode)) {
  445 + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
  446 + }else if ("TCP-ACTIVE".equals(streamMode)) {
  447 + content.append("m=video "+ mediaPort +" TCP/RTP/AVP 96 98 97\r\n");
  448 + }else if("UDP".equals(streamMode)) {
  449 + content.append("m=video "+ mediaPort +" RTP/AVP 96 98 97\r\n");
  450 + }
  451 + content.append("a=recvonly\r\n");
  452 + content.append("a=rtpmap:96 PS/90000\r\n");
  453 + content.append("a=rtpmap:98 H264/90000\r\n");
  454 + content.append("a=rtpmap:97 MPEG4/90000\r\n");
  455 + if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
  456 + content.append("a=setup:passive\r\n");
  457 + content.append("a=connection:new\r\n");
  458 + }else if ("TCP-ACTIVE".equals(streamMode)) { // tcp主动模式
  459 + content.append("a=setup:active\r\n");
  460 + content.append("a=connection:new\r\n");
  461 + }
409 462 }
  463 +
410 464 content.append("y="+ssrc+"\r\n");//ssrc
411 465  
412 466 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null);
413   -
414   - ClientTransaction transaction = transmitRequest(device, request);
415   - streamSession.put(ssrc, transaction);
  467 +
  468 + ClientTransaction transaction = transmitRequest(device, request, errorEvent);
  469 + streamSession.put(streamId, transaction);
416 470  
417 471 } catch ( SipException | ParseException | InvalidArgumentException e) {
418 472 e.printStackTrace();
419 473 }
420 474 }
421   -
  475 +
  476 +
  477 +
422 478 /**
423 479 * 视频流停止
424 480 *
425 481 */
426 482 @Override
427 483 public void streamByeCmd(String ssrc) {
  484 + streamByeCmd(ssrc, null);
  485 + }
  486 + @Override
  487 + public void streamByeCmd(String streamId, SipSubscribe.Event okEvent) {
428 488  
429 489 try {
430   - ClientTransaction transaction = streamSession.get(ssrc);
  490 + ClientTransaction transaction = streamSession.get(streamId);
  491 + // 服务重启后
431 492 if (transaction == null) {
  493 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  494 + if (streamInfo != null) {
  495 +
  496 + }
432 497 return;
433 498 }
434 499  
... ... @@ -436,6 +501,9 @@ public class SIPCommander implements ISIPCommander {
436 501 if (dialog == null) {
437 502 return;
438 503 }
  504 +
  505 +
  506 +
439 507 Request byeRequest = dialog.createRequest(Request.BYE);
440 508 SipURI byeURI = (SipURI) byeRequest.getRequestURI();
441 509 String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString();
... ... @@ -452,8 +520,16 @@ public class SIPCommander implements ISIPCommander {
452 520 } else if("UDP".equals(protocol)) {
453 521 clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest);
454 522 }
  523 +
  524 + CallIdHeader callIdHeader = (CallIdHeader) byeRequest.getHeader(CallIdHeader.NAME);
  525 + if (okEvent != null) {
  526 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
  527 + }
  528 +
455 529 dialog.sendRequest(clientTransaction);
456   - streamSession.remove(ssrc);
  530 +
  531 + streamSession.remove(streamId);
  532 + zlmrtpServerFactory.closeRTPServer(streamId);
457 533 } catch (TransactionDoesNotExistException e) {
458 534 e.printStackTrace();
459 535 } catch (SipException e) {
... ... @@ -571,6 +647,7 @@ public class SIPCommander implements ISIPCommander {
571 647 catalogXml.append("</Query>\r\n");
572 648  
573 649 Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag");
  650 +
574 651 transmitRequest(device, request);
575 652  
576 653 } catch (SipException | ParseException | InvalidArgumentException e) {
... ... @@ -586,7 +663,7 @@ public class SIPCommander implements ISIPCommander {
586 663 * @param device 视频设备
587 664 */
588 665 @Override
589   - public boolean catalogQuery(Device device) {
  666 + public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) {
590 667 // 清空通道
591 668 storager.cleanChannelsForDevice(device.getDeviceId());
592 669 try {
... ... @@ -598,8 +675,9 @@ public class SIPCommander implements ISIPCommander {
598 675 catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
599 676 catalogXml.append("</Query>\r\n");
600 677  
601   - Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", "ToCatalogTag");
602   - transmitRequest(device, request);
  678 + Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaCatalogBranch", "FromCatalogTag", null);
  679 +
  680 + transmitRequest(device, request, errorEvent);
603 681 } catch (SipException | ParseException | InvalidArgumentException e) {
604 682 e.printStackTrace();
605 683 return false;
... ... @@ -631,7 +709,8 @@ public class SIPCommander implements ISIPCommander {
631 709 recordInfoXml.append("<Type>all</Type>\r\n");
632 710 recordInfoXml.append("</Query>\r\n");
633 711  
634   - Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", "ToRecordInfoTag");
  712 + Request request = headerProvider.createMessageRequest(device, recordInfoXml.toString(), "ViaRecordInfoBranch", "FromRecordInfoTag", null);
  713 +
635 714 transmitRequest(device, request);
636 715 } catch (SipException | ParseException | InvalidArgumentException e) {
637 716 e.printStackTrace();
... ... @@ -683,17 +762,45 @@ public class SIPCommander implements ISIPCommander {
683 762 // TODO Auto-generated method stub
684 763 return false;
685 764 }
686   -
  765 +
687 766 private ClientTransaction transmitRequest(Device device, Request request) throws SipException {
  767 + return transmitRequest(device, request, null, null);
  768 + }
  769 +
  770 + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent) throws SipException {
  771 + return transmitRequest(device, request, errorEvent, null);
  772 + }
  773 +
  774 + private ClientTransaction transmitRequest(Device device, Request request, SipSubscribe.Event errorEvent , SipSubscribe.Event okEvent) throws SipException {
688 775 ClientTransaction clientTransaction = null;
689 776 if("TCP".equals(device.getTransport())) {
690 777 clientTransaction = tcpSipProvider.getNewClientTransaction(request);
691 778 } else if("UDP".equals(device.getTransport())) {
692 779 clientTransaction = udpSipProvider.getNewClientTransaction(request);
693 780 }
  781 +
  782 + CallIdHeader callIdHeader = (CallIdHeader)request.getHeader(CallIdHeader.NAME);
  783 + // 添加错误订阅
  784 + if (errorEvent != null) {
  785 + sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), errorEvent);
  786 + }
  787 + // 添加订阅
  788 + if (okEvent != null) {
  789 + sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), okEvent);
  790 + }
  791 +
694 792 clientTransaction.sendRequest();
695 793 return clientTransaction;
696 794 }
697 795  
698 796  
  797 +
  798 +
  799 + @Override
  800 + public void closeRTPServer(Device device, String channelId) {
  801 + if (rtpEnable) {
  802 + String streamId = String.format("gb_play_%s_%s", device.getDeviceId(), channelId);
  803 + zlmrtpServerFactory.closeRTPServer(streamId);
  804 + }
  805 + }
699 806 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/MessageRequestProcessor.java
... ... @@ -10,6 +10,7 @@ import javax.sip.SipException;
10 10 import javax.sip.message.Request;
11 11 import javax.sip.message.Response;
12 12  
  13 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
13 14 import org.dom4j.Document;
14 15 import org.dom4j.DocumentException;
15 16 import org.dom4j.Element;
... ... @@ -48,6 +49,8 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
48 49  
49 50 private IVideoManagerStorager storager;
50 51  
  52 + private IRedisCatchStorage redisCatchStorage;
  53 +
51 54 private EventPublisher publisher;
52 55  
53 56 private RedisUtil redis;
... ... @@ -294,7 +297,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
294 297 device.setStreamMode("UDP");
295 298 }
296 299 storager.updateDevice(device);
297   - cmder.catalogQuery(device);
  300 + cmder.catalogQuery(device, null);
298 301 // 回复200 OK
299 302 responseAck(evt);
300 303 if (offLineDetector.isOnline(deviceId)) {
... ... @@ -315,12 +318,16 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
315 318 try {
316 319 Element rootElement = getRootElement(evt);
317 320 String deviceId = XmlUtil.getText(rootElement, "DeviceID");
318   - // 回复200 OK
319   - responseAck(evt);
320   - if (offLineDetector.isOnline(deviceId)) {
321   - publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
322   - } else {
  321 + // 检查设备是否存在, 不存在则不回复
  322 + if (storager.exists(deviceId)) {
  323 + // 回复200 OK
  324 + responseAck(evt);
  325 + if (offLineDetector.isOnline(deviceId)) {
  326 + publisher.onlineEventPublish(deviceId, VideoManagerConstants.EVENT_ONLINE_KEEPLIVE);
  327 + } else {
  328 + }
323 329 }
  330 +
324 331 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
325 332 e.printStackTrace();
326 333 }
... ... @@ -447,10 +454,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
447 454 String NotifyType =XmlUtil.getText(rootElement, "NotifyType");
448 455 if (NotifyType.equals("121")){
449 456 logger.info("媒体播放完毕,通知关流");
450   - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*");
  457 + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*");
451 458 if (streamInfo != null) {
452   - storager.stopPlayback(streamInfo);
453   - cmder.streamByeCmd(streamInfo.getSsrc());
  459 + redisCatchStorage.stopPlayback(streamInfo);
  460 + cmder.streamByeCmd(streamInfo.getStreamId());
454 461 }
455 462 }
456 463 } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) {
... ... @@ -503,4 +510,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor {
503 510 this.offLineDetector = offLineDetector;
504 511 }
505 512  
  513 + public IRedisCatchStorage getRedisCatchStorage() {
  514 + return redisCatchStorage;
  515 + }
  516 +
  517 + public void setRedisCatchStorage(IRedisCatchStorage redisCatchStorage) {
  518 + this.redisCatchStorage = redisCatchStorage;
  519 + }
506 520 }
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/request/impl/RegisterRequestProcessor.java
... ... @@ -107,17 +107,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
107 107 rPort = viaHeader.getPort();
108 108 }
109 109 //
110   - Host host = new Host();
111   - host.setIp(received);
112   - host.setPort(rPort);
113   - host.setAddress(received.concat(":").concat(String.valueOf(rPort)));
114 110 AddressImpl address = (AddressImpl) fromHeader.getAddress();
115 111 SipUri uri = (SipUri) address.getURI();
116 112 String deviceId = uri.getUser();
117 113 device = new Device();
118 114 device.setStreamMode("UDP");
119 115 device.setDeviceId(deviceId);
120   - device.setHost(host);
  116 + device.setIp(received);
  117 + device.setPort(rPort);
  118 + device.setHostAddress(received.concat(":").concat(String.valueOf(rPort)));
121 119 // 注销成功
122 120 if (expiresHeader != null && expiresHeader.getExpires() == 0) {
123 121 registerFlag = 2;
... ... @@ -141,9 +139,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor {
141 139 // 下发catelog查询目录
142 140 if (registerFlag == 1 && device != null) {
143 141 logger.info("注册成功! deviceId:" + device.getDeviceId());
  142 + boolean exists = storager.exists(device.getDeviceId());
  143 + device.setRegisterTimeMillis(System.currentTimeMillis());
144 144 storager.updateDevice(device);
145 145 publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER);
146   - handler.onRegister(device);
  146 +
  147 + // 只有第一次注册才更新通道
  148 + if (!exists) {
  149 + handler.onRegister(device);
  150 + }
147 151 } else if (registerFlag == 2) {
148 152 logger.info("注销成功! deviceId:" + device.getDeviceId());
149 153 publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER);
... ...
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/response/impl/InviteResponseProcessor.java
... ... @@ -12,6 +12,7 @@ import javax.sip.header.ViaHeader;
12 12 import javax.sip.message.Request;
13 13 import javax.sip.message.Response;
14 14  
  15 +import gov.nist.javax.sip.header.CSeq;
15 16 import org.slf4j.Logger;
16 17 import org.slf4j.LoggerFactory;
17 18 import org.springframework.stereotype.Component;
... ... @@ -23,14 +24,14 @@ import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor;
23 24  
24 25  
25 26 /**
26   - * @Description:处理INVITE响应
  27 + * @Description:处理INVITE响应
27 28 * @author: swwheihei
28   - * @date: 2020年5月3日 下午4:43:52
  29 + * @date: 2020年5月3日 下午4:43:52
29 30 */
30 31 @Component
31 32 public class InviteResponseProcessor implements ISIPResponseProcessor {
32 33  
33   - private final static Logger logger = LoggerFactory.getLogger(SIPProcessorFactory.class);
  34 + private final static Logger logger = LoggerFactory.getLogger(InviteResponseProcessor.class);
34 35  
35 36 /**
36 37 * 处理invite响应
... ... @@ -49,48 +50,16 @@ public class InviteResponseProcessor implements ISIPResponseProcessor {
49 50 // 成功响应
50 51 // 下发ack
51 52 if (statusCode == Response.OK) {
52   - // ClientTransaction clientTransaction = evt.getClientTransaction();
53   - // if(clientTransaction == null){
54   - // logger.error("回复ACK时,clientTransaction为null >>> {}",response);
55   - // return;
56   - // }
57   - // Dialog clientDialog = clientTransaction.getDialog();
58   -
59   - // CSeqHeader clientCSeqHeader = (CSeqHeader)
60   - // response.getHeader(CSeqHeader.NAME);
61   - // long cseqId = clientCSeqHeader.getSeqNumber();
62   - // /*
63   - // createAck函数,创建的ackRequest,会采用Invite响应的200OK,中的contact字段中的地址,作为目标地址。
64   - // 有的终端传上来的可能还是内网地址,会造成ack发送不出去。接受不到音视频流
65   - // 所以在此处统一替换地址。和响应消息的Via头中的地址保持一致。
66   - // */
67   - // Request ackRequest = clientDialog.createAck(cseqId);
68   - // SipURI requestURI = (SipURI) ackRequest.getRequestURI();
69   - // ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
70   - // try {
71   - // requestURI.setHost(viaHeader.getHost());
72   - // } catch (Exception e) {
73   - // e.printStackTrace();
74   - // }
75   - // requestURI.setPort(viaHeader.getPort());
76   - // clientDialog.sendAck(ackRequest);
77   -
78 53 Dialog dialog = evt.getDialog();
79 54 CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
80 55 Request reqAck = dialog.createAck(cseq.getSeqNumber());
81 56  
82 57 SipURI requestURI = (SipURI) reqAck.getRequestURI();
83 58 ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME);
84   - // String viaHost =viaHeader.getHost();
85   - //getHost()函数取回的IP地址是“[xxx.xxx.xxx.xxx:yyyy]”的格式,需用正则表达式截取为“xxx.xxx.xxx.xxx"格式
86   - // Pattern p = Pattern.compile("(?<=//|)((\\w)+\\.)+\\w+");
87   - // Matcher matcher = p.matcher(viaHeader.getHost());
88   - // if (matcher.find()) {
89   - // requestURI.setHost(matcher.group());
90   - // }
91 59 requestURI.setHost(viaHeader.getHost());
92 60 requestURI.setPort(viaHeader.getPort());
93 61 reqAck.setRequestURI(requestURI);
  62 +
94 63 dialog.sendAck(reqAck);
95 64 }
96 65 } catch (InvalidArgumentException | SipException e) {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHTTPProxyController.java
... ... @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
4 4 import com.genersoft.iot.vmp.conf.MediaServerConfig;
  5 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
5 6 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
6 7 import org.slf4j.Logger;
7 8 import org.slf4j.LoggerFactory;
... ... @@ -29,6 +30,9 @@ public class ZLMHTTPProxyController {
29 30 @Autowired
30 31 private IVideoManagerStorager storager;
31 32  
  33 + @Autowired
  34 + private IRedisCatchStorage redisCatchStorage;
  35 +
32 36 @Value("${media.port}")
33 37 private int mediaHttpPort;
34 38  
... ... @@ -36,10 +40,10 @@ public class ZLMHTTPProxyController {
36 40 @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8")
37 41 public Object proxy(HttpServletRequest request, HttpServletResponse response){
38 42  
39   - if (storager.getMediaInfo() == null) {
  43 + if (redisCatchStorage.getMediaInfo() == null) {
40 44 return "未接入流媒体";
41 45 }
42   - MediaServerConfig mediaInfo = storager.getMediaInfo();
  46 + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
43 47 String requestURI = String.format("http://%s:%s%s?%s&%s",
44 48 mediaInfo.getLocalIP(),
45 49 mediaHttpPort,
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
... ... @@ -4,13 +4,17 @@ import java.math.BigInteger;
4 4 import java.text.DecimalFormat;
5 5 import java.util.ArrayList;
6 6 import java.util.List;
  7 +import java.util.UUID;
7 8  
8 9 import com.alibaba.fastjson.JSON;
9 10 import com.alibaba.fastjson.JSONArray;
10 11 import com.genersoft.iot.vmp.common.StreamInfo;
11 12 import com.genersoft.iot.vmp.conf.MediaServerConfig;
  13 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  14 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
12 15 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
13 16 import com.genersoft.iot.vmp.utils.IpUtil;
  17 +import com.genersoft.iot.vmp.vmanager.service.IPlayService;
14 18 import org.slf4j.Logger;
15 19 import org.slf4j.LoggerFactory;
16 20 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -44,14 +48,23 @@ public class ZLMHttpHookListener {
44 48 private SIPCommander cmder;
45 49  
46 50 @Autowired
  51 + private IPlayService playService;
  52 +
  53 + @Autowired
47 54 private IVideoManagerStorager storager;
48 55  
49 56 @Autowired
  57 + private IRedisCatchStorage redisCatchStorage;
  58 +
  59 + @Autowired
50 60 private ZLMRESTfulUtils zlmresTfulUtils;
51 61  
52 62 @Autowired
53 63 private ZLMHttpHookSubscribe subscribe;
54 64  
  65 + @Value("${media.autoApplyPlay}")
  66 + private boolean autoApplyPlay;
  67 +
55 68 @Value("${media.ip}")
56 69 private String mediaIp;
57 70  
... ... @@ -135,34 +148,6 @@ public class ZLMHttpHookListener {
135 148 ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json);
136 149 if (subscribe != null) subscribe.response(json);
137 150  
138   -// if ("rtp".equals(app)) {
139   -// String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
140   -// StreamInfo streamInfoForPlay = storager.queryPlayBySSRC(ssrc);
141   -// if ("rtp".equals(app) && streamInfoForPlay != null ) {
142   -// MediaServerConfig mediaInfo = storager.getMediaInfo();
143   -// streamInfoForPlay.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
144   -// streamInfoForPlay.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
145   -// streamInfoForPlay.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
146   -// streamInfoForPlay.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
147   -// streamInfoForPlay.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
148   -// streamInfoForPlay.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
149   -// streamInfoForPlay.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
150   -// storager.startPlay(streamInfoForPlay);
151   -// }
152   -//
153   -// StreamInfo streamInfoForPlayBack = storager.queryPlaybackBySSRC(ssrc);
154   -// if ("rtp".equals(app) && streamInfoForPlayBack != null ) {
155   -// MediaServerConfig mediaInfo = storager.getMediaInfo();
156   -// streamInfoForPlayBack.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
157   -// streamInfoForPlayBack.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
158   -// streamInfoForPlayBack.setFmp4(String.format("http://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
159   -// streamInfoForPlayBack.setWs_fmp4(String.format("ws://%s:%s/rtp/%s.live.mp4", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
160   -// streamInfoForPlayBack.setRtmp(String.format("rtmp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtmpPort(), streamId));
161   -// streamInfoForPlayBack.setHls(String.format("http://%s:%s/rtp/%s/hls.m3u8", mediaInfo.getWanIp(), mediaInfo.getHttpPort(), streamId));
162   -// streamInfoForPlayBack.setRtsp(String.format("rtsp://%s:%s/rtp/%s", mediaInfo.getWanIp(), mediaInfo.getRtspPort(), streamId));
163   -// storager.startPlayback(streamInfoForPlayBack);
164   -// }
165   -// }
166 151  
167 152 // TODO Auto-generated method stub
168 153  
... ... @@ -268,15 +253,13 @@ public class ZLMHttpHookListener {
268 253 String app = json.getString("app");
269 254 String streamId = json.getString("stream");
270 255 boolean regist = json.getBoolean("regist");
271   -// String ssrc = String.format("%10d", Integer.parseInt(streamId, 16)); // ZLM 要求大写且首位补零
272   - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
273   - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
  256 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
274 257 if ("rtp".equals(app) && !regist ) {
275 258 if (streamInfo!=null){
276   - storager.stopPlay(streamInfo);
  259 + redisCatchStorage.stopPlay(streamInfo);
277 260 }else{
278   - streamInfo = storager.queryPlaybackBySSRC(ssrc);
279   - storager.stopPlayback(streamInfo);
  261 + streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  262 + redisCatchStorage.stopPlayback(streamInfo);
280 263 }
281 264 }
282 265  
... ... @@ -299,17 +282,15 @@ public class ZLMHttpHookListener {
299 282 logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString());
300 283 }
301 284  
302   - BigInteger bigint=new BigInteger(json.getString("stream"), 16);
303   - int numb=bigint.intValue();
304   - String ssrc = String.format("%010d", numb);
305   -
306   - cmder.streamByeCmd(ssrc);
307   - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
  285 + String streamId = json.getString("stream");
  286 +
  287 + cmder.streamByeCmd(streamId);
  288 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
308 289 if (streamInfo!=null){
309   - storager.stopPlay(streamInfo);
  290 + redisCatchStorage.stopPlay(streamInfo);
310 291 }else{
311   - streamInfo = storager.queryPlaybackBySSRC(ssrc);
312   - storager.stopPlayback(streamInfo);
  292 + streamInfo = redisCatchStorage.queryPlaybackByStreamId(streamId);
  293 + redisCatchStorage.stopPlayback(streamInfo);
313 294 }
314 295  
315 296 JSONObject ret = new JSONObject();
... ... @@ -330,7 +311,31 @@ public class ZLMHttpHookListener {
330 311 logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString());
331 312 }
332 313 // TODO Auto-generated method stub
333   -
  314 +
  315 + if (autoApplyPlay) {
  316 + String app = json.getString("app");
  317 + String streamId = json.getString("stream");
  318 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  319 + if ("rtp".equals(app) && streamId.indexOf("gb_play") > -1 && streamInfo == null) {
  320 + String[] s = streamId.split("_");
  321 + if (s.length == 4) {
  322 + String deviceId = s[2];
  323 + String channelId = s[3];
  324 + Device device = storager.queryVideoDevice(deviceId);
  325 + if (device != null) {
  326 + UUID uuid = UUID.randomUUID();
  327 + cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
  328 + logger.info("收到订阅消息: " + response.toJSONString());
  329 + playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  330 + }, null);
  331 + }
  332 +
  333 + }
  334 +
  335 + }
  336 +
  337 + }
  338 +
334 339 JSONObject ret = new JSONObject();
335 340 ret.put("code", 0);
336 341 ret.put("msg", "success");
... ... @@ -354,7 +359,7 @@ public class ZLMHttpHookListener {
354 359 // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0);
355 360 MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class);
356 361 mediaServerConfig.setLocalIP(mediaIp);
357   - storager.updateMediaInfo(mediaServerConfig);
  362 + redisCatchStorage.updateMediaInfo(mediaServerConfig);
358 363 // TODO Auto-generated method stub
359 364  
360 365 JSONObject ret = new JSONObject();
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
... ... @@ -116,4 +116,8 @@ public class ZLMRESTfulUtils {
116 116 public JSONObject openRtpServer(Map<String, Object> param){
117 117 return sendPost("openRtpServer",param);
118 118 }
  119 +
  120 + public JSONObject closeRtpServer(Map<String, Object> param) {
  121 + return sendPost("closeRtpServer",param);
  122 + }
119 123 }
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMUtils.java renamed to src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRTPServerFactory.java
1 1 package com.genersoft.iot.vmp.media.zlm;
2 2  
3 3 import com.alibaba.fastjson.JSONObject;
  4 +import org.slf4j.Logger;
  5 +import org.slf4j.LoggerFactory;
4 6 import org.springframework.beans.factory.annotation.Autowired;
5 7 import org.springframework.beans.factory.annotation.Value;
6 8 import org.springframework.stereotype.Component;
... ... @@ -9,7 +11,9 @@ import java.util.HashMap;
9 11 import java.util.Map;
10 12  
11 13 @Component
12   -public class ZLMUtils {
  14 +public class ZLMRTPServerFactory {
  15 +
  16 + private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory");
13 17  
14 18 @Value("${media.rtp.udpPortRange}")
15 19 private String udpPortRange;
... ... @@ -21,19 +25,54 @@ public class ZLMUtils {
21 25  
22 26 private int currentPort = 0;
23 27  
24   - public int getNewRTPPort(String ssrc) {
25   - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
  28 + public int createRTPServer(String streamId) {
26 29 Map<String, Object> param = new HashMap<>();
  30 + int result = -1;
27 31 int newPort = getPortFromUdpPortRange();
28 32 param.put("port", newPort);
29 33 param.put("enable_tcp", 1);
30 34 param.put("stream_id", streamId);
31 35 JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param);
32   - if (jsonObject != null && jsonObject.getInteger("code") == 0) {
33   - return newPort;
34   - } else {
35   - return getNewRTPPort(ssrc);
  36 + System.out.println(jsonObject);
  37 +
  38 + if (jsonObject != null) {
  39 + switch (jsonObject.getInteger("code")){
  40 + case 0:
  41 + result= newPort;
  42 + break;
  43 + case -300: // id已经存在
  44 + result = newPort;
  45 + break;
  46 + case -400: // 端口占用
  47 + result= createRTPServer(streamId);
  48 + break;
  49 + default:
  50 + logger.error("创建RTP Server 失败: " + jsonObject.getString("msg"));
  51 + break;
  52 + }
  53 + }else {
  54 + // 检查ZLM状态
  55 + logger.error("创建RTP Server 失败: 请检查ZLM服务");
  56 + }
  57 + return result;
  58 + }
  59 +
  60 + public boolean closeRTPServer(String streamId) {
  61 + boolean result = false;
  62 + Map<String, Object> param = new HashMap<>();
  63 + param.put("stream_id", streamId);
  64 + JSONObject jsonObject = zlmresTfulUtils.closeRtpServer(param);
  65 + if (jsonObject != null ) {
  66 + if (jsonObject.getInteger("code") == 0) {
  67 + result = jsonObject.getInteger("hit") == 1;
  68 + }else {
  69 + logger.error("关闭RTP Server 失败: " + jsonObject.getString("msg"));
  70 + }
  71 + }else {
  72 + // 检查ZLM状态
  73 + logger.error("关闭RTP Server 失败: 请检查ZLM服务");
36 74 }
  75 + return result;
37 76 }
38 77  
39 78 private int getPortFromUdpPortRange() {
... ...
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
... ... @@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONArray;
5 5 import com.alibaba.fastjson.JSONObject;
6 6 import com.genersoft.iot.vmp.conf.MediaServerConfig;
  7 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
7 8 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
8 9 import okhttp3.*;
9 10 import org.slf4j.Logger;
... ... @@ -30,6 +31,9 @@ public class ZLMRunner implements CommandLineRunner {
30 31 @Autowired
31 32 private IVideoManagerStorager storager;
32 33  
  34 + @Autowired
  35 + private IRedisCatchStorage redisCatchStorage;
  36 +
33 37 @Value("${media.ip}")
34 38 private String mediaIp;
35 39  
... ... @@ -69,7 +73,7 @@ public class ZLMRunner implements CommandLineRunner {
69 73 logger.info("zlm接入成功...");
70 74 if (autoConfig) saveZLMConfig();
71 75 mediaServerConfig = getMediaServerConfig();
72   - storager.updateMediaInfo(mediaServerConfig);
  76 + redisCatchStorage.updateMediaInfo(mediaServerConfig);
73 77 }
74 78 }
75 79  
... ...
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.conf.MediaServerConfig;
  5 +
  6 +import java.util.Map;
  7 +
  8 +public interface IRedisCatchStorage {
  9 +
  10 + /**
  11 + * 开始播放时将流存入
  12 + *
  13 + * @param stream 流信息
  14 + * @return
  15 + */
  16 + boolean startPlay(StreamInfo stream);
  17 +
  18 +
  19 + /**
  20 + * 停止播放时删除
  21 + *
  22 + * @return
  23 + */
  24 + boolean stopPlay(StreamInfo streamInfo);
  25 +
  26 + /**
  27 + * 查询播放列表
  28 + * @return
  29 + */
  30 + StreamInfo queryPlay(StreamInfo streamInfo);
  31 +
  32 + StreamInfo queryPlayByStreamId(String steamId);
  33 +
  34 + StreamInfo queryPlaybackByStreamId(String steamId);
  35 +
  36 + StreamInfo queryPlayByDevice(String deviceId, String code);
  37 +
  38 + /**
  39 + * 更新流媒体信息
  40 + * @param mediaServerConfig
  41 + * @return
  42 + */
  43 + boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
  44 +
  45 + /**
  46 + * 获取流媒体信息
  47 + * @return
  48 + */
  49 + MediaServerConfig getMediaInfo();
  50 +
  51 + Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
  52 +
  53 + boolean startPlayback(StreamInfo stream);
  54 +
  55 + boolean stopPlayback(StreamInfo streamInfo);
  56 +
  57 + StreamInfo queryPlaybackByDevice(String deviceId, String code);
  58 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/IVideoManagerStorager.java
1 1 package com.genersoft.iot.vmp.storager;
2 2  
3 3 import java.util.List;
4   -import java.util.Map;
5 4  
6   -import com.alibaba.fastjson.JSONObject;
7   -import com.genersoft.iot.vmp.common.PageResult;
8   -import com.genersoft.iot.vmp.common.StreamInfo;
9   -import com.genersoft.iot.vmp.conf.MediaServerConfig;
10 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
11 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
12   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
  7 +import com.github.pagehelper.PageInfo;
13 8  
14 9 /**
15 10 * @Description:视频设备数据存储接口
... ... @@ -18,19 +13,6 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
18 13 */
19 14 public interface IVideoManagerStorager {
20 15  
21   - /**
22   - * 更新流媒体信息
23   - * @param mediaServerConfig
24   - * @return
25   - */
26   - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig);
27   -
28   - /**
29   - * 获取流媒体信息
30   - * @return
31   - */
32   - public MediaServerConfig getMediaInfo();
33   -
34 16 /**
35 17 * 根据设备ID判断设备是否存在
36 18 *
... ... @@ -79,7 +61,7 @@ public interface IVideoManagerStorager {
79 61 * @param count 每页数量
80 62 * @return
81 63 */
82   - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count);
  64 + public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count);
83 65  
84 66 /**
85 67 * 获取某个设备的通道列表
... ... @@ -88,6 +70,7 @@ public interface IVideoManagerStorager {
88 70 * @return
89 71 */
90 72 public List<DeviceChannel> queryChannelsByDeviceId(String deviceId);
  73 +
91 74 /**
92 75 * 获取某个设备的通道
93 76 * @param deviceId 设备ID
... ... @@ -95,21 +78,20 @@ public interface IVideoManagerStorager {
95 78 */
96 79 public DeviceChannel queryChannel(String deviceId, String channelId);
97 80  
98   - /**
  81 + /**
99 82 * 获取多个设备
100   - *
101   - * @param deviceIds 设备ID数组
  83 + * @param page 当前页数
  84 + * @param count 每页数量
102 85 * @return List<Device> 设备对象数组
103 86 */
104   - public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count);
  87 + public PageInfo<Device> queryVideoDeviceList(int page, int count);
105 88  
106 89 /**
107 90 * 获取多个设备
108 91 *
109   - * @param deviceIds 设备ID数组
110 92 * @return List<Device> 设备对象数组
111 93 */
112   - public List<Device> queryVideoDeviceList(String[] deviceIds);
  94 + public List<Device> queryVideoDeviceList();
113 95  
114 96 /**
115 97 * 删除设备
... ... @@ -135,27 +117,6 @@ public interface IVideoManagerStorager {
135 117 */
136 118 public boolean outline(String deviceId);
137 119  
138   - /**
139   - * 开始播放时将流存入
140   - *
141   - * @param stream 流信息
142   - * @return
143   - */
144   - public boolean startPlay(StreamInfo stream);
145   -
146   - /**
147   - * 停止播放时删除
148   - *
149   - * @return
150   - */
151   - public boolean stopPlay(StreamInfo streamInfo);
152   -
153   - /**
154   - * 查找视频流
155   - *
156   - * @return
157   - */
158   - public StreamInfo queryPlay(StreamInfo streamInfo);
159 120  
160 121 /**
161 122 * 查询子设备
... ... @@ -166,12 +127,8 @@ public interface IVideoManagerStorager {
166 127 * @param count
167 128 * @return
168 129 */
169   - PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count);
  130 + PageInfo querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count);
170 131  
171   - /**
172   - * 更新缓存
173   - */
174   - public void updateCatch();
175 132  
176 133 /**
177 134 * 清空通道
... ... @@ -179,45 +136,4 @@ public interface IVideoManagerStorager {
179 136 */
180 137 void cleanChannelsForDevice(String deviceId);
181 138  
182   - StreamInfo queryPlayBySSRC(String ssrc);
183   -
184   - StreamInfo queryPlayByDevice(String deviceId, String code);
185   -
186   - Map<String, StreamInfo> queryPlayByDeviceId(String deviceId);
187   -
188   - boolean startPlayback(StreamInfo streamInfo);
189   -
190   - boolean stopPlayback(StreamInfo streamInfo);
191   -
192   - StreamInfo queryPlaybackByDevice(String deviceId, String channelId);
193   -
194   - StreamInfo queryPlaybackBySSRC(String ssrc);
195   -
196   - /**
197   - * 更新或添加上级平台
198   - * @param parentPlatform
199   - */
200   - boolean updateParentPlatform(ParentPlatform parentPlatform);
201   -
202   - /**
203   - * 删除上级平台
204   - * @param parentPlatform
205   - */
206   - boolean deleteParentPlatform(ParentPlatform parentPlatform);
207   -
208   -
209   - /**
210   - * 分页获取上级平台
211   - * @param page
212   - * @param count
213   - * @return
214   - */
215   - public PageResult<ParentPlatform> queryParentPlatformList(int page, int count);
216   -
217   - /**
218   - * 获取上级平台
219   - * @param platformGbId
220   - * @return
221   - */
222   - public ParentPlatform queryParentPlatById(String platformGbId);
223 139 }
... ...
src/main/java/com/genersoft/iot/vmp/storager/VideoManagerStoragerFactory.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.storager;
2   -
3   -import org.springframework.beans.factory.annotation.Autowired;
4   -import org.springframework.context.annotation.Bean;
5   -import org.springframework.stereotype.Component;
6   -
7   -import com.genersoft.iot.vmp.conf.VManagerConfig;
8   -
9   -/**
10   - * @Description:视频设备数据存储工厂,根据存储策略,返回对应的存储器
11   - * @author: swwheihei
12   - * @date: 2020年5月6日 下午2:15:16
13   - */
14   -@Component
15   -public class VideoManagerStoragerFactory {
16   -
17   - @Autowired
18   - private VManagerConfig vmConfig;
19   -
20   - @Autowired
21   - private IVideoManagerStorager jdbcStorager;
22   -
23   - @Autowired
24   - private IVideoManagerStorager redisStorager;
25   -
26   - @Bean("storager")
27   - public IVideoManagerStorager getStorager() {
28   - if ("redis".equals(vmConfig.getDatabase().toLowerCase())) {
29   - return redisStorager;
30   - } else if ("jdbc".equals(vmConfig.getDatabase().toLowerCase())) {
31   - return jdbcStorager;
32   - }
33   - return redisStorager;
34   - }
35   -
36   -}
src/main/java/com/genersoft/iot/vmp/storager/VodeoMannagerTask.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.storager;
2   -
3   -import org.springframework.beans.factory.annotation.Autowired;
4   -import org.springframework.boot.CommandLineRunner;
5   -import org.springframework.stereotype.Component;
6   -
7   -@Component
8   -public class VodeoMannagerTask implements CommandLineRunner {
9   -
10   - @Autowired
11   - private IVideoManagerStorager storager;
12   -
13   - @Override
14   - public void run(String... strings) throws Exception {
15   - storager.updateCatch();
16   - }
17   -}
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.dao;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  4 +import org.apache.ibatis.annotations.*;
  5 +
  6 +import java.util.List;
  7 +
  8 +/**
  9 + * 用于存储设备通道信息
  10 + */
  11 +@Mapper
  12 +public interface DeviceChannelMapper {
  13 +
  14 + @Insert("INSERT INTO device_channel (channelId, deviceId, name, manufacture, model, owner, civilCode, block, " +
  15 + "address, parental, parentId, safetyWay, registerWay, certNum, certifiable, errCode, secrecy, " +
  16 + "ipAddress, port, password, PTZType, status) " +
  17 + "VALUES ('${channelId}', '${deviceId}', '${name}', '${manufacture}', '${model}', '${owner}', '${civilCode}', '${block}'," +
  18 + "'${address}', ${parental}, '${parentId}', ${safetyWay}, ${registerWay}, '${certNum}', ${certifiable}, ${errCode}, '${secrecy}', " +
  19 + "'${ipAddress}', ${port}, '${password}', ${PTZType}, ${status})")
  20 + int add(DeviceChannel channel);
  21 +
  22 + @Update("UPDATE device_channel " +
  23 + "SET name=#{name}, manufacture=#{manufacture}, model=#{model}, owner=#{owner}, civilCode=#{civilCode}, " +
  24 + "block=#{block}, address=#{address}, parental=#{parental}, parentId=#{parentId}, safetyWay=#{safetyWay}, " +
  25 + "registerWay=#{registerWay}, certNum=#{certNum}, certifiable=#{certifiable}, errCode=#{errCode}, secrecy=#{secrecy}, " +
  26 + "ipAddress=#{ipAddress}, port=#{port}, password=#{password}, PTZType=#{PTZType}, status=#{status}, streamId=#{streamId}, " +
  27 + "hasAudio=#{hasAudio}" +
  28 + "WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
  29 + int update(DeviceChannel channel);
  30 +
  31 + @Select(value = {" <script>" +
  32 + "SELECT * FROM ( "+
  33 + " SELECT * , (SELECT count(0) FROM device_channel WHERE parentId=dc.channelId) as subCount FROM device_channel dc " +
  34 + " WHERE dc.deviceId=#{deviceId} " +
  35 + " <if test=\"query != null\"> AND (dc.channelId LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
  36 + " <if test=\"parentChannelId != null\"> AND dc.parentId=#{parentChannelId} </if> " +
  37 + " <if test=\"online == true\" > AND dc.status=1</if>" +
  38 + " <if test=\"online == false\" > AND dc.status=0</if>) dcr" +
  39 + " WHERE 1=1 " +
  40 + " <if test=\"hasSubChannel == true\" > AND subCount >0</if>" +
  41 + " <if test=\"hasSubChannel == false\" > AND subCount=0</if>" +
  42 + " </script>"})
  43 + List<DeviceChannel> queryChannelsByDeviceId(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, Boolean online);
  44 +
  45 + @Select("SELECT * FROM device_channel WHERE deviceId=#{deviceId} AND channelId=#{channelId}")
  46 + DeviceChannel queryChannel(String deviceId, String channelId);
  47 +
  48 + @Delete("DELETE FROM device_channel WHERE deviceId=#{deviceId}")
  49 + int cleanChannelsByDeviceId(String deviceId);
  50 +
  51 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.dao;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  4 +import org.apache.ibatis.annotations.*;
  5 +import org.springframework.stereotype.Repository;
  6 +
  7 +import java.util.List;
  8 +
  9 +/**
  10 + * 用于存储设备信息
  11 + */
  12 +@Mapper
  13 +@Repository
  14 +public interface DeviceMapper {
  15 +
  16 + @Select("SELECT * FROM device WHERE deviceId = #{deviceId}")
  17 + Device getDeviceByDeviceId(String deviceId);
  18 +
  19 + @Insert("INSERT INTO device (" +
  20 + "deviceId, " +
  21 + "name, " +
  22 + "manufacturer, " +
  23 + "model, " +
  24 + "firmware, " +
  25 + "transport," +
  26 + "streamMode," +
  27 + "ip," +
  28 + "port," +
  29 + "hostAddress," +
  30 + "online" +
  31 + ") VALUES (" +
  32 + "#{deviceId}," +
  33 + "#{name}," +
  34 + "#{manufacturer}," +
  35 + "#{model}," +
  36 + "#{firmware}," +
  37 + "#{transport}," +
  38 + "#{streamMode}," +
  39 + "#{ip}," +
  40 + "#{port}," +
  41 + "#{hostAddress}," +
  42 + "#{online}" +
  43 + ")")
  44 + int add(Device device);
  45 +
  46 +
  47 + @Update("UPDATE device " +
  48 + "SET name=#{name}, " +
  49 + "manufacturer=#{manufacturer}," +
  50 + "model=#{model}," +
  51 + "firmware=#{firmware}, " +
  52 + "transport=#{transport}," +
  53 + "streamMode=#{streamMode}, " +
  54 + "ip=#{ip}, " +
  55 + "port=#{port}, " +
  56 + "hostAddress=#{hostAddress}, " +
  57 + "online=#{online} " +
  58 + "WHERE deviceId=#{deviceId}")
  59 + int update(Device device);
  60 +
  61 + @Select("SELECT *, (SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount FROM device de")
  62 + List<Device> getDevices();
  63 +
  64 + @Delete("DELETE FROM device WHERE deviceId=#{deviceId}")
  65 + int del(String deviceId);
  66 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.impl;
  2 +
  3 +import com.genersoft.iot.vmp.common.StreamInfo;
  4 +import com.genersoft.iot.vmp.common.VideoManagerConstants;
  5 +import com.genersoft.iot.vmp.conf.MediaServerConfig;
  6 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  7 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
  8 +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
  9 +import com.genersoft.iot.vmp.utils.redis.RedisUtil;
  10 +import org.springframework.beans.factory.annotation.Autowired;
  11 +import org.springframework.stereotype.Component;
  12 +
  13 +import java.util.HashMap;
  14 +import java.util.HashSet;
  15 +import java.util.List;
  16 +import java.util.Map;
  17 +
  18 +@Component
  19 +public class RedisCatchStorageImpl implements IRedisCatchStorage {
  20 +
  21 + @Autowired
  22 + private RedisUtil redis;
  23 +
  24 + @Autowired
  25 + private DeviceChannelMapper deviceChannelMapper;
  26 +
  27 +
  28 + /**
  29 + * 开始播放时将流存入redis
  30 + *
  31 + * @return
  32 + */
  33 + @Override
  34 + public boolean startPlay(StreamInfo stream) {
  35 + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
  36 + stream);
  37 + }
  38 +
  39 + /**
  40 + * 停止播放时从redis删除
  41 + *
  42 + * @return
  43 + */
  44 + @Override
  45 + public boolean stopPlay(StreamInfo streamInfo) {
  46 + if (streamInfo == null) return false;
  47 + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
  48 + if (deviceChannel != null) {
  49 + deviceChannel.setStreamId(null);
  50 + deviceChannel.setDeviceId(streamInfo.getDeviceID());
  51 + deviceChannelMapper.update(deviceChannel);
  52 + }
  53 + return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
  54 + streamInfo.getStreamId(),
  55 + streamInfo.getDeviceID(),
  56 + streamInfo.getCahnnelId()));
  57 + }
  58 +
  59 + /**
  60 + * 查询播放列表
  61 + * @return
  62 + */
  63 + @Override
  64 + public StreamInfo queryPlay(StreamInfo streamInfo) {
  65 + return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
  66 + VideoManagerConstants.PLAYER_PREFIX,
  67 + streamInfo.getStreamId(),
  68 + streamInfo.getDeviceID(),
  69 + streamInfo.getCahnnelId()));
  70 + }
  71 + @Override
  72 + public StreamInfo queryPlayByStreamId(String steamId) {
  73 + List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, steamId));
  74 + if (playLeys == null || playLeys.size() == 0) return null;
  75 + return (StreamInfo)redis.get(playLeys.get(0).toString());
  76 + }
  77 +
  78 + @Override
  79 + public StreamInfo queryPlaybackByStreamId(String steamId) {
  80 + List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, steamId));
  81 + if (playLeys == null || playLeys.size() == 0) return null;
  82 + return (StreamInfo)redis.get(playLeys.get(0).toString());
  83 + }
  84 +
  85 + @Override
  86 + public StreamInfo queryPlayByDevice(String deviceId, String code) {
  87 +// List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
  88 + List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
  89 + deviceId,
  90 + code));
  91 + if (playLeys == null || playLeys.size() == 0) return null;
  92 + return (StreamInfo)redis.get(playLeys.get(0).toString());
  93 + }
  94 +
  95 + /**
  96 + * 更新流媒体信息
  97 + * @param mediaServerConfig
  98 + * @return
  99 + */
  100 + @Override
  101 + public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
  102 + return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
  103 + }
  104 +
  105 + /**
  106 + * 获取流媒体信息
  107 + * @return
  108 + */
  109 + @Override
  110 + public MediaServerConfig getMediaInfo() {
  111 + return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
  112 + }
  113 +
  114 + @Override
  115 + public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
  116 + Map<String, StreamInfo> streamInfos = new HashMap<>();
  117 +// List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
  118 + List<Object> players = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
  119 + if (players.size() == 0) return streamInfos;
  120 + for (int i = 0; i < players.size(); i++) {
  121 + String key = (String) players.get(i);
  122 + StreamInfo streamInfo = (StreamInfo)redis.get(key);
  123 + streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo);
  124 + }
  125 + return streamInfos;
  126 + }
  127 +
  128 +
  129 + @Override
  130 + public boolean startPlayback(StreamInfo stream) {
  131 + return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getStreamId(),stream.getDeviceID(), stream.getCahnnelId()),
  132 + stream);
  133 + }
  134 +
  135 +
  136 + @Override
  137 + public boolean stopPlayback(StreamInfo streamInfo) {
  138 + if (streamInfo == null) return false;
  139 + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
  140 + if (deviceChannel != null) {
  141 + deviceChannel.setStreamId(null);
  142 + deviceChannel.setDeviceId(streamInfo.getDeviceID());
  143 + deviceChannelMapper.update(deviceChannel);
  144 + }
  145 + return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  146 + streamInfo.getStreamId(),
  147 + streamInfo.getDeviceID(),
  148 + streamInfo.getCahnnelId()));
  149 + }
  150 +
  151 + @Override
  152 + public StreamInfo queryPlaybackByDevice(String deviceId, String code) {
  153 + String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  154 + deviceId,
  155 + code);
  156 + List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  157 + deviceId,
  158 + code));
  159 + if (playLeys == null || playLeys.size() == 0) {
  160 + playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
  161 + deviceId));
  162 + }
  163 + if (playLeys == null || playLeys.size() == 0) return null;
  164 + return (StreamInfo)redis.get(playLeys.get(0).toString());
  165 + }
  166 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/impl/VideoManagerStoragerImpl.java 0 → 100644
  1 +package com.genersoft.iot.vmp.storager.impl;
  2 +
  3 +import java.util.*;
  4 +
  5 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  6 +import com.genersoft.iot.vmp.storager.dao.DeviceChannelMapper;
  7 +import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
  8 +import com.github.pagehelper.PageHelper;
  9 +import com.github.pagehelper.PageInfo;
  10 +import io.swagger.models.auth.In;
  11 +import org.springframework.beans.factory.annotation.Autowired;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import com.genersoft.iot.vmp.gb28181.bean.Device;
  15 +import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
  16 +import org.springframework.util.StringUtils;
  17 +
  18 +/**
  19 + * @Description:视频设备数据存储-jdbc实现
  20 + * @author: swwheihei
  21 + * @date: 2020年5月6日 下午2:31:42
  22 + */
  23 +@Component
  24 +public class VideoManagerStoragerImpl implements IVideoManagerStorager {
  25 +
  26 + @Autowired
  27 + private DeviceMapper deviceMapper;
  28 +
  29 + @Autowired
  30 + private DeviceChannelMapper deviceChannelMapper;
  31 +
  32 +
  33 + /**
  34 + * 根据设备ID判断设备是否存在
  35 + *
  36 + * @param deviceId 设备ID
  37 + * @return true:存在 false:不存在
  38 + */
  39 + @Override
  40 + public boolean exists(String deviceId) {
  41 + return deviceMapper.getDeviceByDeviceId(deviceId) != null;
  42 + }
  43 +
  44 + /**
  45 + * 视频设备创建
  46 + *
  47 + * @param device 设备对象
  48 + * @return true:创建成功 false:创建失败
  49 + */
  50 + @Override
  51 + public synchronized boolean create(Device device) {
  52 + return deviceMapper.add(device) > 0;
  53 + }
  54 +
  55 +
  56 +
  57 + /**
  58 + * 视频设备更新
  59 + *
  60 + * @param device 设备对象
  61 + * @return true:更新成功 false:更新失败
  62 + */
  63 + @Override
  64 + public synchronized boolean updateDevice(Device device) {
  65 + Device deviceByDeviceId = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
  66 + if (deviceByDeviceId == null) {
  67 + return deviceMapper.add(device) > 0;
  68 + }else {
  69 + return deviceMapper.update(device) > 0;
  70 + }
  71 +
  72 + }
  73 +
  74 + @Override
  75 + public synchronized void updateChannel(String deviceId, DeviceChannel channel) {
  76 + String channelId = channel.getChannelId();
  77 + channel.setDeviceId(deviceId);
  78 + DeviceChannel deviceChannel = deviceChannelMapper.queryChannel(deviceId, channelId);
  79 + if (deviceChannel == null) {
  80 + deviceChannelMapper.add(channel);
  81 + }else {
  82 + deviceChannelMapper.update(channel);
  83 + }
  84 + }
  85 +
  86 + /**
  87 + * 获取设备
  88 + *
  89 + * @param deviceId 设备ID
  90 + * @return Device 设备对象
  91 + */
  92 + @Override
  93 + public Device queryVideoDevice(String deviceId) {
  94 + return deviceMapper.getDeviceByDeviceId(deviceId);
  95 + }
  96 +
  97 + @Override
  98 + public PageInfo queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, Boolean online, int page, int count) {
  99 + // 获取到所有正在播放的流
  100 + PageHelper.startPage(page, count);
  101 + List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, null, query, hasSubChannel, online);
  102 + return new PageInfo<>(all);
  103 + }
  104 +
  105 +
  106 +
  107 + @Override
  108 + public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
  109 + return deviceChannelMapper.queryChannelsByDeviceId(deviceId, null,null, null, null);
  110 + }
  111 +
  112 + @Override
  113 + public PageInfo<DeviceChannel> querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
  114 + PageHelper.startPage(page, count);
  115 + List<DeviceChannel> all = deviceChannelMapper.queryChannelsByDeviceId(deviceId, parentChannelId, null, null, null);
  116 + return new PageInfo<>(all);
  117 + }
  118 +
  119 + @Override
  120 + public DeviceChannel queryChannel(String deviceId, String channelId) {
  121 + return deviceChannelMapper.queryChannel(deviceId, channelId);
  122 + }
  123 +
  124 +
  125 + /**
  126 + * 获取多个设备
  127 + *
  128 + * @param page 当前页数
  129 + * @param count 每页数量
  130 + * @return PageInfo<Device> 分页设备对象数组
  131 + */
  132 + @Override
  133 + public PageInfo<Device> queryVideoDeviceList(int page, int count) {
  134 + PageHelper.startPage(page, count);
  135 + List<Device> all = deviceMapper.getDevices();
  136 + return new PageInfo<>(all);
  137 + }
  138 +
  139 + /**
  140 + * 获取多个设备
  141 + *
  142 + * @return List<Device> 设备对象数组
  143 + */
  144 + @Override
  145 + public List<Device> queryVideoDeviceList() {
  146 +
  147 + List<Device> deviceList = deviceMapper.getDevices();
  148 + return deviceList;
  149 + }
  150 +
  151 + /**
  152 + * 删除设备
  153 + *
  154 + * @param deviceId 设备ID
  155 + * @return true:删除成功 false:删除失败
  156 + */
  157 + @Override
  158 + public boolean delete(String deviceId) {
  159 + int result = deviceMapper.del(deviceId);
  160 +
  161 + return result > 0;
  162 + }
  163 +
  164 + /**
  165 + * 更新设备在线
  166 + *
  167 + * @param deviceId 设备ID
  168 + * @return true:更新成功 false:更新失败
  169 + */
  170 + @Override
  171 + public synchronized boolean online(String deviceId) {
  172 + Device device = deviceMapper.getDeviceByDeviceId(deviceId);
  173 + device.setOnline(1);
  174 + System.out.println("更新设备在线");
  175 + if (device == null) {
  176 + return false;
  177 + }
  178 + return deviceMapper.update(device) > 0;
  179 + }
  180 +
  181 + /**
  182 + * 更新设备离线
  183 + *
  184 + * @param deviceId 设备ID
  185 + * @return true:更新成功 false:更新失败
  186 + */
  187 + @Override
  188 + public synchronized boolean outline(String deviceId) {
  189 + Device device = deviceMapper.getDeviceByDeviceId(deviceId);
  190 + device.setOnline(0);
  191 + System.out.println("更新设备离线");
  192 + return deviceMapper.update(device) > 0;
  193 + }
  194 +
  195 +
  196 + @Override
  197 + public void cleanChannelsForDevice(String deviceId) {
  198 + int result = deviceChannelMapper.cleanChannelsByDeviceId(deviceId);
  199 + }
  200 +
  201 +
  202 +}
... ...
src/main/java/com/genersoft/iot/vmp/storager/jdbc/VideoManagerJdbcStoragerImpl.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.storager.jdbc;
2   -
3   -import java.util.List;
4   -import java.util.Map;
5   -
6   -import com.genersoft.iot.vmp.common.PageResult;
7   -import com.genersoft.iot.vmp.common.StreamInfo;
8   -import com.genersoft.iot.vmp.conf.MediaServerConfig;
9   -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
10   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
11   -import org.springframework.stereotype.Component;
12   -import org.springframework.stereotype.Service;
13   -
14   -import com.genersoft.iot.vmp.common.VideoManagerConstants;
15   -import com.genersoft.iot.vmp.gb28181.bean.Device;
16   -import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
17   -
18   -/**
19   - * @Description:视频设备数据存储-jdbc实现
20   - * @author: swwheihei
21   - * @date: 2020年5月6日 下午2:28:12
22   - */
23   -@Component("jdbcStorager")
24   -public class VideoManagerJdbcStoragerImpl implements IVideoManagerStorager {
25   -
26   - @Override
27   - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
28   - return false;
29   - }
30   -
31   - @Override
32   - public MediaServerConfig getMediaInfo() {
33   - return null;
34   - }
35   -
36   - /**
37   - * 根据设备ID判断设备是否存在
38   - *
39   - * @param deviceId 设备ID
40   - * @return true:存在 false:不存在
41   - */
42   - @Override
43   - public boolean exists(String deviceId) {
44   - // TODO Auto-generated method stub
45   - return false;
46   - }
47   -
48   - /**
49   - * 视频设备创建
50   - *
51   - * @param device 设备对象
52   - * @return true:创建成功 false:创建失败
53   - */
54   - @Override
55   - public boolean create(Device device) {
56   - // TODO Auto-generated method stub
57   - return false;
58   - }
59   -
60   - @Override
61   - public boolean updateDevice(Device device) {
62   - return false;
63   - }
64   -
65   - @Override
66   - public void updateChannel(String deviceId, DeviceChannel channel) {
67   -
68   - }
69   -
70   -
71   - /**
72   - * 获取设备
73   - *
74   - * @param deviceId 设备ID
75   - * @return Device 设备对象
76   - */
77   - @Override
78   - public Device queryVideoDevice(String deviceId) {
79   - // TODO Auto-generated method stub
80   - return null;
81   - }
82   -
83   - @Override
84   - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) {
85   - return null;
86   - }
87   -
88   -
89   - @Override
90   - public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
91   - return null;
92   - }
93   -
94   - @Override
95   - public DeviceChannel queryChannel(String deviceId, String channelId) {
96   - return null;
97   - }
98   -
99   - @Override
100   - public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
101   - return null;
102   - }
103   -
104   - /**
105   - * 获取多个设备
106   - *
107   - * @param deviceIds 设备ID数组
108   - * @return List<Device> 设备对象数组
109   - */
110   - @Override
111   - public List<Device> queryVideoDeviceList(String[] deviceIds) {
112   - // TODO Auto-generated method stub
113   - return null;
114   - }
115   -
116   - /**
117   - * 删除设备
118   - *
119   - * @param deviceId 设备ID
120   - * @return true:删除成功 false:删除失败
121   - */
122   - @Override
123   - public boolean delete(String deviceId) {
124   - // TODO Auto-generated method stub
125   - return false;
126   - }
127   -
128   - /**
129   - * 更新设备在线
130   - *
131   - * @param deviceId 设备ID
132   - * @return true:更新成功 false:更新失败
133   - */
134   - @Override
135   - public boolean online(String deviceId) {
136   - // TODO Auto-generated method stub
137   - return false;
138   - }
139   -
140   - /**
141   - * 更新设备离线
142   - *
143   - * @param deviceId 设备ID
144   - * @return true:更新成功 false:更新失败
145   - */
146   - @Override
147   - public boolean outline(String deviceId) {
148   - // TODO Auto-generated method stub
149   - return false;
150   - }
151   -
152   - @Override
153   - public boolean stopPlay(StreamInfo streamInfo) {
154   - return false;
155   - }
156   -
157   - @Override
158   - public StreamInfo queryPlay(StreamInfo streamInfo) {
159   - return null;
160   - }
161   -
162   - @Override
163   - public PageResult querySubChannels(String deviceId, String channelId, String query, Boolean hasSubChannel, String online, int page, int count) {
164   - return null;
165   - }
166   -
167   - @Override
168   - public void updateCatch() {
169   - System.out.println("##################");
170   - }
171   -
172   - @Override
173   - public void cleanChannelsForDevice(String deviceId) {
174   -
175   - }
176   -
177   - @Override
178   - public boolean startPlay(StreamInfo stream) {
179   - return false;
180   - }
181   -
182   - @Override
183   - public StreamInfo queryPlayBySSRC(String ssrc) {
184   - return null;
185   - }
186   -
187   - @Override
188   - public StreamInfo queryPlayByDevice(String deviceId, String code) {
189   - return null;
190   - }
191   -
192   - @Override
193   - public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
194   -
195   - return null;
196   - }
197   -
198   - @Override
199   - public boolean startPlayback(StreamInfo streamInfo) {
200   - return false;
201   - }
202   -
203   - @Override
204   - public boolean stopPlayback(StreamInfo streamInfo) {
205   - return false;
206   - }
207   -
208   - @Override
209   - public StreamInfo queryPlaybackByDevice(String deviceId, String channelId) {
210   - return null;
211   - }
212   -
213   - @Override
214   - public StreamInfo queryPlaybackBySSRC(String ssrc) {
215   - return null;
216   - }
217   -
218   - @Override
219   - public boolean updateParentPlatform(ParentPlatform parentPlatform) {
220   - return false;
221   - }
222   -
223   - @Override
224   - public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
225   - return false;
226   - }
227   -
228   - @Override
229   - public PageResult<ParentPlatform> queryParentPlatformList(int page, int count) {
230   - return null;
231   - }
232   -
233   - @Override
234   - public ParentPlatform queryParentPlatById(String platformGbId) {
235   - return null;
236   - }
237   -}
src/main/java/com/genersoft/iot/vmp/storager/redis/VideoManagerRedisStoragerImpl.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.storager.redis;
2   -
3   -import java.util.*;
4   -
5   -import com.alibaba.fastjson.JSON;
6   -import com.alibaba.fastjson.JSONObject;
7   -import com.genersoft.iot.vmp.common.PageResult;
8   -import com.genersoft.iot.vmp.common.StreamInfo;
9   -import com.genersoft.iot.vmp.conf.MediaServerConfig;
10   -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
11   -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
12   -import org.springframework.beans.factory.annotation.Autowired;
13   -import org.springframework.stereotype.Component;
14   -
15   -import com.genersoft.iot.vmp.common.VideoManagerConstants;
16   -import com.genersoft.iot.vmp.gb28181.bean.Device;
17   -import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
18   -import com.genersoft.iot.vmp.utils.redis.RedisUtil;
19   -import org.springframework.util.StringUtils;
20   -
21   -/**
22   - * @Description:视频设备数据存储-redis实现
23   - * @author: swwheihei
24   - * @date: 2020年5月6日 下午2:31:42
25   - */
26   -@Component("redisStorager")
27   -public class VideoManagerRedisStoragerImpl implements IVideoManagerStorager {
28   -
29   - @Autowired
30   - private RedisUtil redis;
31   -
32   - private HashMap<String, HashMap<String, HashSet<String>>> deviceMap = new HashMap<>();
33   -
34   -
35   - /**
36   - * 根据设备ID判断设备是否存在
37   - *
38   - * @param deviceId 设备ID
39   - * @return true:存在 false:不存在
40   - */
41   - @Override
42   - public boolean exists(String deviceId) {
43   - return redis.hasKey(VideoManagerConstants.DEVICE_PREFIX+deviceId);
44   - }
45   -
46   - /**
47   - * 视频设备创建
48   - *
49   - * @param device 设备对象
50   - * @return true:创建成功 false:创建失败
51   - */
52   - @Override
53   - public boolean create(Device device) {
54   - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
55   - }
56   -
57   -
58   -
59   - /**
60   - * 视频设备更新
61   - *
62   - * @param device 设备对象
63   - * @return true:更新成功 false:更新失败
64   - */
65   - @Override
66   - public boolean updateDevice(Device device) {
67   - if (deviceMap.get(device.getDeviceId()) == null) {
68   - deviceMap.put(device.getDeviceId(), new HashMap<String, HashSet<String>>());
69   - }
70   - // 更新device中的通道数量
71   - device.setChannelCount(deviceMap.get(device.getDeviceId()).size());
72   - // 存储device
73   - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
74   -
75   -
76   - }
77   -
78   - @Override
79   - public void updateChannel(String deviceId, DeviceChannel channel) {
80   - String channelId = channel.getChannelId();
81   - HashMap<String, HashSet<String>> channelMap = deviceMap.get(deviceId);
82   - if (channelMap == null) return;
83   - // 作为父设备, 确定自己的子节点数
84   - if (channelMap.get(channelId) == null) {
85   - channelMap.put(channelId, new HashSet<String>());
86   - }else if (channelMap.get(channelId).size() > 0) {
87   - channel.setSubCount(channelMap.get(channelId).size());
88   - }
89   -
90   - // 存储通道
91   - redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
92   - "_" + channel.getChannelId() +
93   - "_" + (channel.getStatus() == 1 ? "on":"off") +
94   - "_" + (channelMap.get(channelId).size() > 0)+
95   - "_" + (StringUtils.isEmpty(channel.getParentId())?null:channel.getParentId()),
96   - channel);
97   - // 更新device中的通道数量
98   - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
99   - device.setChannelCount(deviceMap.get(deviceId).size());
100   - redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
101   -
102   -
103   - // 如果有父设备,更新父设备内子节点数
104   - String parentId = channel.getParentId();
105   - if (!StringUtils.isEmpty(parentId) && !parentId.equals(deviceId)) {
106   -
107   - if (channelMap.get(parentId) == null) {
108   - channelMap.put(parentId, new HashSet<String>());
109   - }
110   - channelMap.get(parentId).add(channelId);
111   -
112   - DeviceChannel deviceChannel = queryChannel(deviceId, parentId);
113   - if (deviceChannel != null) {
114   - deviceChannel.setSubCount(channelMap.get(parentId).size());
115   - redis.set(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
116   - "_" + deviceChannel.getChannelId() +
117   - "_" + (deviceChannel.getStatus() == 1 ? "on":"off") +
118   - "_" + (channelMap.get(deviceChannel.getChannelId()).size() > 0)+
119   - "_" + (StringUtils.isEmpty(deviceChannel.getParentId())?null:deviceChannel.getParentId()),
120   - deviceChannel);
121   -
122   - }
123   - }
124   -
125   - }
126   -
127   - /**
128   - * 获取设备
129   - *
130   - * @param deviceId 设备ID
131   - * @return Device 设备对象
132   - */
133   - @Override
134   - public Device queryVideoDevice(String deviceId) {
135   - return (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
136   - }
137   -
138   - @Override
139   - public PageResult queryChannelsByDeviceId(String deviceId, String query, Boolean hasSubChannel, String online, int page, int count) {
140   - // 获取到所有正在播放的流
141   - Map<String, StreamInfo> stringStreamInfoMap = queryPlayByDeviceId(deviceId);
142   - List<DeviceChannel> result = new ArrayList<>();
143   - PageResult pageResult = new PageResult<DeviceChannel>();
144   - String queryContent = "*";
145   - if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query);
146   - String queryHasSubChannel = "*";
147   - if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false";
148   - String queryOnline = "*";
149   - if (!StringUtils.isEmpty(online)) queryOnline = online;
150   - String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
151   - "_" + queryContent + // 搜索编号和名称
152   - "_" + queryOnline + // 搜索是否在线
153   - "_" + queryHasSubChannel + // 搜索是否含有子节点
154   - "_" + "*";
155   -// List<Object> deviceChannelList = redis.keys(queryStr);
156   - List<Object> deviceChannelList = redis.scan(queryStr);
157   - //对查询结果排序,避免出现通道排列顺序乱序的情况
158   - Collections.sort(deviceChannelList,new Comparator<Object>(){
159   - @Override
160   - public int compare(Object o1, Object o2) {
161   - return o1.toString().compareToIgnoreCase(o2.toString());
162   - }
163   - });
164   - pageResult.setPage(page);
165   - pageResult.setCount(count);
166   - pageResult.setTotal(deviceChannelList.size());
167   - int maxCount = (page + 1 ) * count;
168   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
169   - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
170   - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
171   - StreamInfo streamInfo = stringStreamInfoMap.get(deviceId + "_" + deviceChannel.getChannelId());
172   - deviceChannel.setPlay(streamInfo != null);
173   - if (streamInfo != null) deviceChannel.setSsrc(streamInfo.getSsrc());
174   - result.add(deviceChannel);
175   - }
176   - pageResult.setData(result);
177   - }
178   -
179   - return pageResult;
180   - }
181   -
182   -
183   -
184   - @Override
185   - public List<DeviceChannel> queryChannelsByDeviceId(String deviceId) {
186   - List<DeviceChannel> result = new ArrayList<>();
187   -// List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
188   - List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
189   -
190   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
191   - for (int i = 0; i < deviceChannelList.size(); i++) {
192   - result.add((DeviceChannel)redis.get((String) deviceChannelList.get(i)));
193   - }
194   - }
195   - return result;
196   - }
197   -
198   - @Override
199   - public PageResult querySubChannels(String deviceId, String parentChannelId, String query, Boolean hasSubChannel, String online, int page, int count) {
200   - List<DeviceChannel> allDeviceChannels = new ArrayList<>();
201   - String queryContent = "*";
202   - if (!StringUtils.isEmpty(query)) queryContent = String.format("*%S*",query);
203   - String queryHasSubChannel = "*";
204   - if (hasSubChannel != null) queryHasSubChannel = hasSubChannel?"true":"false";
205   - String queryOnline = "*";
206   - if (!StringUtils.isEmpty(online)) queryOnline = online;
207   - String queryStr = VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
208   - "_" + queryContent + // 搜索编号和名称
209   - "_" + queryOnline + // 搜索是否在线
210   - "_" + queryHasSubChannel + // 搜索是否含有子节点
211   - "_" + parentChannelId;
212   -
213   -// List<Object> deviceChannelList = redis.keys(queryStr);
214   - List<Object> deviceChannelList = redis.scan(queryStr);
215   -
216   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
217   - for (int i = 0; i < deviceChannelList.size(); i++) {
218   - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
219   - if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) {
220   - allDeviceChannels.add(deviceChannel);
221   - }
222   - }
223   - }
224   - int maxCount = (page + 1 ) * count;
225   - PageResult pageResult = new PageResult<DeviceChannel>();
226   - pageResult.setPage(page);
227   - pageResult.setCount(count);
228   - pageResult.setTotal(allDeviceChannels.size());
229   -
230   - if (allDeviceChannels.size() > 0) {
231   - pageResult.setData(allDeviceChannels.subList(
232   - page * count, pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal()
233   - ));
234   - }
235   - return pageResult;
236   - }
237   -
238   - public List<DeviceChannel> querySubChannels(String deviceId, String parentChannelId) {
239   - List<DeviceChannel> allDeviceChannels = new ArrayList<>();
240   -// List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
241   - List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
242   -
243   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
244   - for (int i = 0; i < deviceChannelList.size(); i++) {
245   - DeviceChannel deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(i));
246   - if (deviceChannel.getParentId() != null && deviceChannel.getParentId().equals(parentChannelId)) {
247   - allDeviceChannels.add(deviceChannel);
248   - }
249   - }
250   - }
251   -
252   - return allDeviceChannels;
253   - }
254   -
255   - @Override
256   - public DeviceChannel queryChannel(String deviceId, String channelId) {
257   - DeviceChannel deviceChannel = null;
258   -// List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
259   - List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId +
260   - "_" + channelId + "*");
261   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
262   - deviceChannel = (DeviceChannel)redis.get((String)deviceChannelList.get(0));
263   - }
264   - return deviceChannel;
265   - }
266   -
267   -
268   - /**
269   - * 获取多个设备
270   - *
271   - * @param deviceIds 设备ID数组
272   - * @return List<Device> 设备对象数组
273   - */
274   - @Override
275   - public PageResult<Device> queryVideoDeviceList(String[] deviceIds, int page, int count) {
276   - List<Device> devices = new ArrayList<>();
277   - PageResult pageResult = new PageResult<Device>();
278   - pageResult.setPage(page);
279   - pageResult.setCount(count);
280   - Device device = null;
281   -
282   - if (deviceIds == null || deviceIds.length == 0) {
283   -
284   -// List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
285   - List<Object> deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*");
286   - pageResult.setTotal(deviceIdList.size());
287   - int maxCount = (page + 1)* count;
288   - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
289   - // devices.add((Device)redis.get((String)deviceIdList.get(i)));
290   - device =(Device)redis.get((String)deviceIdList.get(i));
291   - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
292   - // outline(device.getDeviceId());
293   - }
294   - devices.add(device);
295   - }
296   - } else {
297   - for (int i = 0; i < deviceIds.length; i++) {
298   - // devices.add((Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]));
299   - device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]);
300   - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
301   - // outline(device.getDeviceId());
302   - }
303   - devices.add(device);
304   - }
305   - }
306   - pageResult.setData(devices);
307   - return pageResult;
308   - }
309   -
310   - /**
311   - * 获取多个设备
312   - *
313   - * @param deviceIds 设备ID数组
314   - * @return List<Device> 设备对象数组
315   - */
316   - @Override
317   - public List<Device> queryVideoDeviceList(String[] deviceIds) {
318   - List<Device> devices = new ArrayList<>();
319   - Device device = null;
320   -
321   - if (deviceIds == null || deviceIds.length == 0) {
322   -// List<Object> deviceIdList = redis.keys(VideoManagerConstants.DEVICE_PREFIX+"*");
323   - List<Object> deviceIdList = redis.scan(VideoManagerConstants.DEVICE_PREFIX+"*");
324   - for (int i = 0; i < deviceIdList.size(); i++) {
325   - device =(Device)redis.get((String)deviceIdList.get(i));
326   - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
327   - outline(device.getDeviceId());
328   - }
329   - devices.add(device);
330   - }
331   - } else {
332   - for (int i = 0; i < deviceIds.length; i++) {
333   - device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceIds[i]);
334   - if (redis.scan(VideoManagerConstants.KEEPLIVEKEY_PREFIX+device.getDeviceId()).size() == 0){
335   - outline(device.getDeviceId());
336   - }
337   - devices.add(device);
338   - }
339   - }
340   - return devices;
341   - }
342   -
343   - /**
344   - * 删除设备
345   - *
346   - * @param deviceId 设备ID
347   - * @return true:删除成功 false:删除失败
348   - */
349   - @Override
350   - public boolean delete(String deviceId) {
351   - return redis.del(VideoManagerConstants.DEVICE_PREFIX+deviceId);
352   - }
353   -
354   - /**
355   - * 更新设备在线
356   - *
357   - * @param deviceId 设备ID
358   - * @return true:更新成功 false:更新失败
359   - */
360   - @Override
361   - public boolean online(String deviceId) {
362   - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
363   - device.setOnline(1);
364   - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
365   - }
366   -
367   - /**
368   - * 更新设备离线
369   - *
370   - * @param deviceId 设备ID
371   - * @return true:更新成功 false:更新失败
372   - */
373   - @Override
374   - public boolean outline(String deviceId) {
375   - Device device = (Device)redis.get(VideoManagerConstants.DEVICE_PREFIX+deviceId);
376   - if (device == null) return false;
377   - device.setOnline(0);
378   - return redis.set(VideoManagerConstants.DEVICE_PREFIX+device.getDeviceId(), device);
379   - }
380   -
381   - /**
382   - * 开始播放时将流存入redis
383   - *
384   - * @return
385   - */
386   - @Override
387   - public boolean startPlay(StreamInfo stream) {
388   - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
389   - stream);
390   - }
391   -
392   - /**
393   - * 停止播放时从redis删除
394   - *
395   - * @return
396   - */
397   - @Override
398   - public boolean stopPlay(StreamInfo streamInfo) {
399   - if (streamInfo == null) return false;
400   - DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
401   - if (deviceChannel != null) {
402   - deviceChannel.setSsrc(null);
403   - deviceChannel.setPlay(false);
404   - updateChannel(streamInfo.getDeviceID(), deviceChannel);
405   - }
406   - return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
407   - streamInfo.getSsrc(),
408   - streamInfo.getDeviceID(),
409   - streamInfo.getCahnnelId()));
410   - }
411   -
412   - /**
413   - * 查询播放列表
414   - * @return
415   - */
416   - @Override
417   - public StreamInfo queryPlay(StreamInfo streamInfo) {
418   - return (StreamInfo)redis.get(String.format("%S_%s_%s_%s",
419   - VideoManagerConstants.PLAYER_PREFIX,
420   - streamInfo.getSsrc(),
421   - streamInfo.getDeviceID(),
422   - streamInfo.getCahnnelId()));
423   - }
424   - @Override
425   - public StreamInfo queryPlayBySSRC(String ssrc) {
426   -// List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
427   - List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
428   - if (playLeys == null || playLeys.size() == 0) return null;
429   - return (StreamInfo)redis.get(playLeys.get(0).toString());
430   - }
431   -
432   - @Override
433   - public StreamInfo queryPlaybackBySSRC(String ssrc) {
434   -// List<Object> playLeys = redis.keys(String.format("%S_%s_*", VideoManagerConstants.PLAYER_PREFIX, ssrc));
435   - List<Object> playLeys = redis.scan(String.format("%S_%s_*", VideoManagerConstants.PLAY_BLACK_PREFIX, ssrc));
436   - if (playLeys == null || playLeys.size() == 0) return null;
437   - return (StreamInfo)redis.get(playLeys.get(0).toString());
438   - }
439   -
440   - @Override
441   - public StreamInfo queryPlayByDevice(String deviceId, String code) {
442   -// List<Object> playLeys = redis.keys(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
443   - List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAYER_PREFIX,
444   - deviceId,
445   - code));
446   - if (playLeys == null || playLeys.size() == 0) return null;
447   - return (StreamInfo)redis.get(playLeys.get(0).toString());
448   - }
449   -
450   - /**
451   - * 更新流媒体信息
452   - * @param mediaServerConfig
453   - * @return
454   - */
455   - @Override
456   - public boolean updateMediaInfo(MediaServerConfig mediaServerConfig) {
457   - return redis.set(VideoManagerConstants.MEDIA_SERVER_PREFIX,mediaServerConfig);
458   - }
459   -
460   - /**
461   - * 获取流媒体信息
462   - * @return
463   - */
464   - @Override
465   - public MediaServerConfig getMediaInfo() {
466   - return (MediaServerConfig)redis.get(VideoManagerConstants.MEDIA_SERVER_PREFIX);
467   - }
468   -
469   - @Override
470   - public void updateCatch() {
471   - deviceMap = new HashMap<>();
472   - // 更新设备
473   - List<Device> devices = queryVideoDeviceList(null);
474   - if (devices == null && devices.size() == 0) return;
475   - for (Device device : devices) {
476   - // 更新设备下的通道
477   - HashMap<String, HashSet<String>> channelMap = new HashMap<String, HashSet<String>>();
478   - List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX +
479   - device.getDeviceId() + "_" + "*");
480   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
481   - for (int i = 0; i < deviceChannelList.size(); i++) {
482   - String key = (String)deviceChannelList.get(i);
483   - String[] s = key.split("_");
484   - String channelId = s[3];
485   - HashSet<String> subChannel = channelMap.get(channelId);
486   - if (subChannel == null) {
487   - subChannel = new HashSet<>();
488   - }
489   - System.out.println(key);
490   - if (s.length == 6 && !"null".equals(s[5])) {
491   - subChannel.add(s[5]);
492   - }
493   - channelMap.put(channelId, subChannel);
494   - }
495   - }
496   - deviceMap.put(device.getDeviceId(),channelMap);
497   - }
498   - System.out.println();
499   - }
500   -
501   - @Override
502   - public void cleanChannelsForDevice(String deviceId) {
503   - List<DeviceChannel> result = new ArrayList<>();
504   -// List<Object> deviceChannelList = redis.keys(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
505   - List<Object> deviceChannelList = redis.scan(VideoManagerConstants.CACHEKEY_PREFIX + deviceId + "_" + "*");
506   - if (deviceChannelList != null && deviceChannelList.size() > 0 ) {
507   - for (int i = 0; i < deviceChannelList.size(); i++) {
508   - redis.del((String)deviceChannelList.get(i));
509   - }
510   - }
511   - }
512   -
513   - @Override
514   - public Map<String, StreamInfo> queryPlayByDeviceId(String deviceId) {
515   - Map<String, StreamInfo> streamInfos = new HashMap<>();
516   -// List<Object> playLeys = redis.keys(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
517   - List<Object> playLeys = redis.scan(String.format("%S_*_%S_*", VideoManagerConstants.PLAYER_PREFIX, deviceId));
518   - if (playLeys.size() == 0) return streamInfos;
519   - for (int i = 0; i < playLeys.size(); i++) {
520   - String key = (String) playLeys.get(i);
521   - StreamInfo streamInfo = (StreamInfo)redis.get(key);
522   - streamInfos.put(streamInfo.getDeviceID() + "_" + streamInfo.getCahnnelId(), streamInfo);
523   - }
524   - return streamInfos;
525   - }
526   -
527   -
528   - @Override
529   - public boolean startPlayback(StreamInfo stream) {
530   - return redis.set(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX, stream.getSsrc(),stream.getDeviceID(), stream.getCahnnelId()),
531   - stream);
532   - }
533   -
534   -
535   - @Override
536   - public boolean stopPlayback(StreamInfo streamInfo) {
537   - if (streamInfo == null) return false;
538   - DeviceChannel deviceChannel = queryChannel(streamInfo.getDeviceID(), streamInfo.getCahnnelId());
539   - if (deviceChannel != null) {
540   - deviceChannel.setSsrc(null);
541   - deviceChannel.setPlay(false);
542   - updateChannel(streamInfo.getDeviceID(), deviceChannel);
543   - }
544   - return redis.del(String.format("%S_%s_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
545   - streamInfo.getSsrc(),
546   - streamInfo.getDeviceID(),
547   - streamInfo.getCahnnelId()));
548   - }
549   -
550   - @Override
551   - public StreamInfo queryPlaybackByDevice(String deviceId, String code) {
552   - String format = String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
553   - deviceId,
554   - code);
555   - List<Object> playLeys = redis.scan(String.format("%S_*_%s_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
556   - deviceId,
557   - code));
558   - if (playLeys == null || playLeys.size() == 0) {
559   - playLeys = redis.scan(String.format("%S_*_*_%s", VideoManagerConstants.PLAY_BLACK_PREFIX,
560   - deviceId));
561   - }
562   - if (playLeys == null || playLeys.size() == 0) return null;
563   - return (StreamInfo)redis.get(playLeys.get(0).toString());
564   - }
565   -
566   - @Override
567   - public boolean updateParentPlatform(ParentPlatform parentPlatform) {
568   -
569   - // 存储device
570   - return redis.set(VideoManagerConstants.PLATFORM_PREFIX + parentPlatform.getDeviceGBId(), parentPlatform);
571   - }
572   -
573   - @Override
574   - public boolean deleteParentPlatform(ParentPlatform parentPlatform) {
575   - return redis.del(VideoManagerConstants.PLATFORM_PREFIX + parentPlatform.getDeviceGBId());
576   - }
577   -
578   - @Override
579   - public PageResult<ParentPlatform> queryParentPlatformList(int page, int count) {
580   - PageResult pageResult = new PageResult<Device>();
581   - pageResult.setPage(page);
582   - pageResult.setCount(count);
583   - List<ParentPlatform> resultData = new ArrayList<>();
584   - List<Object> parentPlatformList = redis.scan(VideoManagerConstants.PLATFORM_PREFIX + "*");
585   - pageResult.setTotal(parentPlatformList.size());
586   - int maxCount = (page + 1)* count;
587   - for (int i = page * count; i < (pageResult.getTotal() > maxCount ? maxCount : pageResult.getTotal() ); i++) {
588   - ParentPlatform parentPlatform =(ParentPlatform)redis.get((String)parentPlatformList.get(i));
589   - resultData.add(parentPlatform);
590   -
591   - }
592   - pageResult.setData(resultData);
593   - return pageResult;
594   - }
595   -
596   - @Override
597   - public ParentPlatform queryParentPlatById(String platformGbId) {
598   - return (ParentPlatform)redis.get(VideoManagerConstants.PLATFORM_PREFIX + platformGbId);
599   - }
600   -}
src/main/java/com/genersoft/iot/vmp/utils/SpringBeanFactory.java
... ... @@ -34,6 +34,7 @@ public class SpringBeanFactory implements ApplicationContextAware {
34 34 * 获取对象 这里重写了bean方法,起主要作用
35 35 */
36 36 public static Object getBean(String beanId) throws BeansException {
  37 + if (applicationContext == null) return null;
37 38 return applicationContext.getBean(beanId);
38 39 }
39 40  
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
1 1 package com.genersoft.iot.vmp.vmanager.device;
2 2  
3   -import java.util.List;
4   -
5   -import com.genersoft.iot.vmp.common.PageResult;
6 3 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
  4 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  5 +import com.github.pagehelper.PageInfo;
7 6 import org.slf4j.Logger;
8 7 import org.slf4j.LoggerFactory;
9 8 import org.springframework.beans.factory.annotation.Autowired;
10 9 import org.springframework.http.HttpStatus;
11 10 import org.springframework.http.ResponseEntity;
  11 +import org.springframework.util.StringUtils;
12 12 import org.springframework.web.bind.annotation.*;
13 13 import org.springframework.web.context.request.async.DeferredResult;
14 14  
... ... @@ -19,6 +19,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
19 19 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
20 20 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
21 21  
  22 +import javax.sip.message.Response;
  23 +
22 24 @CrossOrigin
23 25 @RestController
24 26 @RequestMapping("/api")
... ... @@ -50,13 +52,13 @@ public class DeviceController {
50 52 }
51 53  
52 54 @GetMapping("/devices")
53   - public PageResult<Device> devices(int page, int count){
  55 + public PageInfo<Device> devices(int page, int count){
54 56  
55 57 if (logger.isDebugEnabled()) {
56 58 logger.debug("查询所有视频设备API调用");
57 59 }
58 60  
59   - return storager.queryVideoDeviceList(null, page, count);
  61 + return storager.queryVideoDeviceList(page, count);
60 62 }
61 63  
62 64 /**
... ... @@ -66,18 +68,33 @@ public class DeviceController {
66 68 * @param count 每页条数
67 69 * @return 通道列表
68 70 */
  71 + /**
  72 + * 分页查询通道数
  73 + *
  74 + * @param deviceId 设备id
  75 + * @param page 当前页
  76 + * @param count 每页条数
  77 + * @param query 查询内容
  78 + * @param online 是否在线 在线 true / 离线 false
  79 + * @param channelType 设备 false/子目录 true
  80 + * @return 通道列表
  81 + */
69 82 @GetMapping("/devices/{deviceId}/channels")
70   - public ResponseEntity<PageResult> channels(@PathVariable String deviceId,
  83 + public ResponseEntity<PageInfo> channels(@PathVariable String deviceId,
71 84 int page, int count,
72 85 @RequestParam(required = false) String query,
73   - @RequestParam(required = false) String online,
  86 + @RequestParam(required = false) Boolean online,
74 87 @RequestParam(required = false) Boolean channelType
75 88 ){
76 89  
77 90 if (logger.isDebugEnabled()) {
78 91 logger.debug("查询所有视频设备API调用");
79 92 }
80   - PageResult pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
  93 + if (StringUtils.isEmpty(query)) {
  94 + query = null;
  95 + }
  96 +
  97 + PageInfo pageResult = storager.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count);
81 98 return new ResponseEntity<>(pageResult,HttpStatus.OK);
82 99 }
83 100  
... ... @@ -86,11 +103,25 @@ public class DeviceController {
86 103  
87 104 if (logger.isDebugEnabled()) {
88 105 }
89   - logger.debug("设备信息同步API调用,deviceId:" + deviceId);
  106 + logger.debug("设备通道信息同步API调用,deviceId:" + deviceId);
90 107  
91 108 Device device = storager.queryVideoDevice(deviceId);
92   - cmder.catalogQuery(device);
93   - DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>();
  109 + cmder.catalogQuery(device, event -> {
  110 + Response response = event.getResponse();
  111 + RequestMessage msg = new RequestMessage();
  112 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
  113 + msg.setData(String.format("同步通道失败,错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  114 + resultHolder.invokeResult(msg);
  115 + });
  116 + DeferredResult<ResponseEntity<Device>> result = new DeferredResult<ResponseEntity<Device>>(2*1000L);
  117 + result.onTimeout(()->{
  118 + logger.warn(String.format("设备通道信息同步超时"));
  119 + // 释放rtpserver
  120 + RequestMessage msg = new RequestMessage();
  121 + msg.setId(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId);
  122 + msg.setData("Timeout");
  123 + resultHolder.invokeResult(msg);
  124 + });
94 125 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result);
95 126 return result;
96 127 }
... ... @@ -124,7 +155,7 @@ public class DeviceController {
124 155 * @return 子通道列表
125 156 */
126 157 @GetMapping("/subChannels/{deviceId}/{channelId}/channels")
127   - public ResponseEntity<PageResult> subChannels(@PathVariable String deviceId,
  158 + public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId,
128 159 @PathVariable String channelId,
129 160 int page,
130 161 int count,
... ... @@ -137,23 +168,23 @@ public class DeviceController {
137 168 }
138 169 DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId);
139 170 if (deviceChannel == null) {
140   - PageResult<DeviceChannel> deviceChannelPageResult = new PageResult<>();
  171 + PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>();
141 172 return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK);
142 173 }
143 174  
144   - PageResult pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
  175 + PageInfo pageResult = storager.querySubChannels(deviceId, channelId, query, channelType, online, page, count);
145 176 return new ResponseEntity<>(pageResult,HttpStatus.OK);
146 177 }
147 178  
148 179 @PostMapping("/channel/update/{deviceId}")
149   - public ResponseEntity<PageResult> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
  180 + public ResponseEntity<PageInfo> updateChannel(@PathVariable String deviceId,DeviceChannel channel){
150 181 storager.updateChannel(deviceId, channel);
151 182 return new ResponseEntity<>(null,HttpStatus.OK);
152 183 }
153 184  
154 185 @GetMapping("/devices/{deviceId}/transport/{streamMode}")
155 186 @PostMapping("/devices/{deviceId}/transport/{streamMode}")
156   - public ResponseEntity<PageResult> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){
  187 + public ResponseEntity<PageInfo> updateTransport(@PathVariable String deviceId, @PathVariable String streamMode){
157 188 Device device = storager.queryVideoDevice(deviceId);
158 189 device.setStreamMode(streamMode);
159 190 storager.updateDevice(device);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/Device.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.vmanager.device.entity;
2   -
3   -import java.util.List;
4   -
5   -import javax.persistence.Column;
6   -import javax.persistence.Id;
7   -import javax.persistence.Table;
8   -import javax.persistence.Transient;
9   -import javax.validation.constraints.Max;
10   -import javax.validation.constraints.NotNull;
11   -import javax.validation.constraints.Size;
12   -
13   -import io.swagger.annotations.ApiModel;
14   -import io.swagger.annotations.ApiModelProperty;
15   -
16   -/**
17   - * @Description:视频设备信息
18   - * @author: songww
19   - * @date: 2020年5月8日 下午2:05:56
20   - */
21   -@ApiModel(value = "视频设备信息", description = "视频设备信息")
22   -@Table(name="VMP_VIDEODEVICES")
23   -public class Device {
24   -
25   - /**
26   - * 设备Id
27   - */
28   - @ApiModelProperty("设备编号")
29   - @Id
30   - @Column(name="DEVICE_ID")
31   - @NotNull(message = "deviceId 不能为 null")
32   - @Size(min = 4, max = 32, message = "deviceId 必须大于 4 位并且小于 32 位")
33   - private String deviceId;
34   -
35   - /**
36   - * 设备名称
37   - */
38   - @ApiModelProperty("设备名称")
39   - @Column(name="DEVICE_NAME")
40   - @Size(max = 32, message = "deviceName 必须小于 32 位")
41   - private String deviceName;
42   -
43   - /**
44   - * 生产厂商
45   - */
46   - @ApiModelProperty("生产厂商")
47   - @Column(name="MANUFACTURER")
48   - @Size(max = 64, message = "manufacturer 必须小于 64 位")
49   - private String manufacturer;
50   -
51   - /**
52   - * 型号
53   - */
54   - @ApiModelProperty("型号")
55   - @Column(name="MODEL")
56   - @Size(max = 64, message = "manufacturer 必须小于 64 位")
57   - private String model;
58   -
59   - /**
60   - * 固件版本
61   - */
62   - @ApiModelProperty("固件版本")
63   - @Column(name="FIRMWARE")
64   - @Size(max = 64, message = "firmware 必须小于 64 位")
65   - private String firmware;
66   -
67   - /**
68   - * 通信协议
69   - * GB28181 ONVIF
70   - */
71   - @ApiModelProperty("通信协议")
72   - @Column(name="PROTOCOL")
73   - @NotNull(message = "protocol 不能为 null")
74   - @Size(max = 16, message = "protocol 必须小于 16 位")
75   - private String protocol;
76   -
77   - /**
78   - * SIP 传输协议
79   - * UDP/TCP
80   - */
81   - @ApiModelProperty("SIP 传输协议")
82   - @Column(name="TRANSPORT")
83   - @Size(min = 3,max = 3 ,message = "transport 必须为 3 位")
84   - private String transport;
85   -
86   - /**
87   - * 数据流传输模式
88   - * UDP:udp传输
89   - * TCP-ACTIVE:tcp主动模式
90   - * TCP-PASSIVE:tcp被动模式
91   - */
92   - @ApiModelProperty("数据流传输模式")
93   - @Column(name="STREAM_MODE")
94   - @Size(max = 64, message = "streamMode 必须小于 16 位")
95   - private String streamMode;
96   -
97   - /**
98   - * IP地址
99   - */
100   - @ApiModelProperty("IP地址")
101   - @Column(name="IP")
102   - @Size(max = 15, message = "streamMode 必须小于 15 位")
103   - private String ip;
104   -
105   - /**
106   - * 端口号
107   - */
108   - @ApiModelProperty("端口号")
109   - @Column(name="PORT")
110   - @Max(value = 65535,message = "port 最大值为 65535")
111   - private Integer port;
112   -
113   - /**
114   - * 在线状态 1在线, 0离线
115   - */
116   - @ApiModelProperty("在线状态")
117   - @Size(min = 1,max = 1 ,message = "online 必须为 1 位")
118   - @Column(name="ONLINE")
119   - private String online;
120   -
121   - /**
122   - * 通道数量
123   - */
124   - @ApiModelProperty("通道数量")
125   - @Column(name="CHANNEL_SUM")
126   - @Max(value = 1000000000,message = "channelSum 最大值为 1000000000")
127   - private Integer channelSum;
128   -
129   - @Override
130   - public String toString() {
131   - return "Device{" +
132   - "deviceId='" + deviceId + '\'' +
133   - ", deviceName='" + deviceName + '\'' +
134   - ", manufacturer='" + manufacturer + '\'' +
135   - ", model='" + model + '\'' +
136   - ", firmware='" + firmware + '\'' +
137   - ", protocol='" + protocol + '\'' +
138   - ", transport='" + transport + '\'' +
139   - ", streamMode='" + streamMode + '\'' +
140   - ", ip='" + ip + '\'' +
141   - ", port=" + port +
142   - ", online='" + online + '\'' +
143   - ", channelSum=" + channelSum +
144   - ", createTime='" + createTime + '\'' +
145   - ", registerTime='" + registerTime + '\'' +
146   - ", heartbeatTime='" + heartbeatTime + '\'' +
147   - ", updateTime='" + updateTime + '\'' +
148   - ", updatePerson='" + updatePerson + '\'' +
149   - ", syncTime='" + syncTime + '\'' +
150   - ", syncPerson='" + syncPerson + '\'' +
151   - ", username='" + username + '\'' +
152   - ", password='" + password + '\'' +
153   - ", channelList=" + channelList +
154   - '}';
155   - }
156   -
157   - /**
158   - * 创建时间
159   - */
160   - @ApiModelProperty("创建时间")
161   - @Column(name="CREATE_TIME")
162   - private String createTime;
163   -
164   - /**
165   - * 注册时间
166   - */
167   - @ApiModelProperty("注册时间")
168   - @Column(name="REGISTER_TIME")
169   - private String registerTime;
170   -
171   - /**
172   - * 心跳时间
173   - */
174   - @ApiModelProperty("心跳时间")
175   - @Column(name="HEARTBEAT_TIME")
176   - private String heartbeatTime;
177   -
178   - /**
179   - * 修改时间
180   - */
181   - @ApiModelProperty("更新时间")
182   - @Column(name="UPDATE_TIME")
183   - private String updateTime;
184   -
185   - /**
186   - * 修改人
187   - */
188   - @ApiModelProperty("修改人")
189   - @Column(name="UPDATE_PERSON")
190   - private String updatePerson;
191   -
192   - /**
193   - * 同步时间
194   - */
195   - @ApiModelProperty("同步时间")
196   - @Column(name="SYNC_TIME")
197   - private String syncTime;
198   -
199   - /**
200   - * 同步人
201   - */
202   - @ApiModelProperty("同步人")
203   - @Column(name="SYNC_PERSON")
204   - private String syncPerson;
205   -
206   - /**
207   - * ONVIF协议-用户名
208   - */
209   - @ApiModelProperty("用户名")
210   - @Column(name="USERNAME")
211   - @Size(max = 32, message = "username 必须小于 32 位")
212   - private String username;
213   -
214   - /**
215   - * ONVIF协议-密码
216   - */
217   - @ApiModelProperty("密码")
218   - @Size(max = 32, message = "password 必须小于 32 位")
219   - @Column(name="PASSWORD")
220   - private String password;
221   -
222   - @Transient
223   - private List<DeviceChannel> channelList;
224   -
225   -
226   - public String getDeviceId() {
227   - return deviceId;
228   - }
229   -
230   - public void setDeviceId(String deviceId) {
231   - this.deviceId = deviceId;
232   - }
233   -
234   - public String getDeviceName() {
235   - return deviceName;
236   - }
237   -
238   - public void setDeviceName(String deviceName) {
239   - this.deviceName = deviceName;
240   - }
241   -
242   - public String getManufacturer() {
243   - return manufacturer;
244   - }
245   -
246   - public void setManufacturer(String manufacturer) {
247   - this.manufacturer = manufacturer;
248   - }
249   -
250   - public String getModel() {
251   - return model;
252   - }
253   -
254   - public void setModel(String model) {
255   - this.model = model;
256   - }
257   -
258   - public String getFirmware() {
259   - return firmware;
260   - }
261   -
262   - public void setFirmware(String firmware) {
263   - this.firmware = firmware;
264   - }
265   -
266   - public String getProtocol() {
267   - return protocol;
268   - }
269   -
270   - public void setProtocol(String protocol) {
271   - this.protocol = protocol;
272   - }
273   -
274   - public String getTransport() {
275   - return transport;
276   - }
277   -
278   - public void setTransport(String transport) {
279   - this.transport = transport;
280   - }
281   -
282   - public String getStreamMode() {
283   - return streamMode;
284   - }
285   -
286   - public void setStreamMode(String streamMode) {
287   - this.streamMode = streamMode;
288   - }
289   -
290   - public String getIp() {
291   - return ip;
292   - }
293   -
294   - public void setIp(String ip) {
295   - this.ip = ip;
296   - }
297   -
298   - public Integer getPort() {
299   - return port;
300   - }
301   -
302   - public void setPort(Integer port) {
303   - this.port = port;
304   - }
305   -
306   - public String getOnline() {
307   - return online;
308   - }
309   -
310   - public void setOnline(String online) {
311   - this.online = online;
312   - }
313   -
314   - public Integer getChannelSum() {
315   - return channelSum;
316   - }
317   -
318   - public void setChannelSum(Integer channelSum) {
319   - this.channelSum = channelSum;
320   - }
321   -
322   - public String getCreateTime() {
323   - return createTime;
324   - }
325   -
326   - public void setCreateTime(String createTime) {
327   - this.createTime = createTime;
328   - }
329   -
330   - public String getRegisterTime() {
331   - return registerTime;
332   - }
333   -
334   - public void setRegisterTime(String registerTime) {
335   - this.registerTime = registerTime;
336   - }
337   -
338   - public String getHeartbeatTime() {
339   - return heartbeatTime;
340   - }
341   -
342   - public void setHeartbeatTime(String heartbeatTime) {
343   - this.heartbeatTime = heartbeatTime;
344   - }
345   -
346   - public String getUpdateTime() {
347   - return updateTime;
348   - }
349   -
350   - public void setUpdateTime(String updateTime) {
351   - this.updateTime = updateTime;
352   - }
353   -
354   - public String getUpdatePerson() {
355   - return updatePerson;
356   - }
357   -
358   - public void setUpdatePerson(String updatePerson) {
359   - this.updatePerson = updatePerson;
360   - }
361   -
362   - public String getSyncTime() {
363   - return syncTime;
364   - }
365   -
366   - public void setSyncTime(String syncTime) {
367   - this.syncTime = syncTime;
368   - }
369   -
370   - public String getSyncPerson() {
371   - return syncPerson;
372   - }
373   -
374   - public void setSyncPerson(String syncPerson) {
375   - this.syncPerson = syncPerson;
376   - }
377   -
378   - public String getUsername() {
379   - return username;
380   - }
381   -
382   - public void setUsername(String username) {
383   - this.username = username;
384   - }
385   -
386   - public String getPassword() {
387   - return password;
388   - }
389   -
390   - public void setPassword(String password) {
391   - this.password = password;
392   - }
393   -
394   - public List<DeviceChannel> getChannelList() {
395   - return channelList;
396   - }
397   -
398   - public void setChannelList(List<DeviceChannel> channelList) {
399   - this.channelList = channelList;
400   - }
401   -}
src/main/java/com/genersoft/iot/vmp/vmanager/device/entity/DeviceChannel.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.vmanager.device.entity;
2   -
3   -import javax.persistence.Column;
4   -import javax.persistence.Id;
5   -import javax.persistence.Table;
6   -
7   -import io.swagger.annotations.ApiModel;
8   -import io.swagger.annotations.ApiModelProperty;
9   -
10   -/**
11   - * @Description:设备通道信息
12   - * @author: songww
13   - * @date: 2020年5月20日 下午9:00:46
14   - */
15   -@ApiModel(value = "设备通道信息", description = "设备通道信息")
16   -@Table(name="VMP_VIDEOCHANNELS")
17   -public class DeviceChannel {
18   -
19   - /**
20   - * 通道编号
21   - */
22   - @ApiModelProperty("通道编号")
23   - @Id
24   - @Column(name="CHANNEL_ID")
25   - private String channelId;
26   -
27   - /**
28   - * 设备编号
29   - */
30   - @ApiModelProperty("设备编号")
31   - @Column(name="DEVICE_ID")
32   - private String deviceId;
33   -
34   - /**
35   - * 通道名
36   - */
37   - @ApiModelProperty("通道名")
38   - @Column(name="CHANNEL_NAME")
39   - private String channelName;
40   -
41   - /**
42   - * 生产厂商
43   - */
44   - @ApiModelProperty("生产厂商")
45   - @Column(name="MANUFACTURER")
46   - private String manufacture;
47   -
48   - /**
49   - * 型号
50   - */
51   - @ApiModelProperty("型号")
52   - @Column(name="MODEL")
53   - private String model;
54   -
55   - /**
56   - * 设备归属
57   - */
58   - @ApiModelProperty("设备归属")
59   - @Column(name="OWNER")
60   - private String owner;
61   -
62   - /**
63   - * 行政区域
64   - */
65   - @ApiModelProperty("行政区域")
66   - @Column(name="CIVIL_CODE")
67   - private String civilCode;
68   -
69   - /**
70   - * 警区
71   - */
72   - @ApiModelProperty("警区")
73   - @Column(name="BLOCK")
74   - private String block;
75   -
76   - /**
77   - * 安装地址
78   - */
79   - @ApiModelProperty("安装地址")
80   - @Column(name="ADDRESS")
81   - private String address;
82   -
83   - /**
84   - * 是否有子设备 1有, 0没有
85   - */
86   - @ApiModelProperty("是否有子设备")
87   - @Column(name="PARENTAL")
88   - private String parental;
89   -
90   - /**
91   - * 父级id
92   - */
93   - @ApiModelProperty("父级编码")
94   - @Column(name="PARENT_ID")
95   - private String parentId;
96   -
97   - /**
98   - * 信令安全模式 缺省为0; 0:不采用; 2: S/MIME签名方式; 3: S/ MIME加密签名同时采用方式; 4:数字摘要方式
99   - */
100   - @ApiModelProperty("信令安全模式")
101   - @Column(name="SAFETY_WAY")
102   - private String safetyWay;
103   -
104   - /**
105   - * 注册方式 缺省为1;1:符合IETFRFC3261标准的认证注册模 式; 2:基于口令的双向认证注册模式; 3:基于数字证书的双向认证注册模式
106   - */
107   - @ApiModelProperty("注册方式")
108   - @Column(name="REGISTER_WAY")
109   - private String registerWay;
110   -
111   - /**
112   - * 证书序列号
113   - */
114   - @ApiModelProperty("证书序列号")
115   - @Column(name="CERT_NUM")
116   - private String certNum;
117   -
118   - /**
119   - * 证书有效标识 缺省为0;证书有效标识:0:无效1: 有效
120   - */
121   - @ApiModelProperty("证书有效标识")
122   - @Column(name="CERT_VALID")
123   - private String certValid;
124   -
125   - /**
126   - * 证书无效原因码
127   - */
128   - @ApiModelProperty("证书无效原因码")
129   - @Column(name="CERT_ERRCODE")
130   - private String certErrCode;
131   -
132   - /**
133   - * 证书终止有效期
134   - */
135   - @ApiModelProperty("证书终止有效期")
136   - @Column(name="CERT_ENDTIME")
137   - private String certEndTime;
138   -
139   - /**
140   - * 保密属性 缺省为0; 0:不涉密, 1:涉密
141   - */
142   - @ApiModelProperty("保密属性")
143   - @Column(name="SECRECY")
144   - private String secrecy;
145   -
146   - /**
147   - * IP地址
148   - */
149   - @ApiModelProperty("IP地址")
150   - @Column(name="IP")
151   - private String ip;
152   -
153   - /**
154   - * 端口号
155   - */
156   - @ApiModelProperty("端口号")
157   - @Column(name="PORT")
158   - private Integer port;
159   -
160   - /**
161   - * 密码
162   - */
163   - @ApiModelProperty("密码")
164   - @Column(name="PASSWORD")
165   - private String password;
166   -
167   - /**
168   - * 在线/离线
169   - * 1在线,0离线
170   - * 默认在线
171   - * 信令:
172   - * <Status>ON</Status>
173   - * <Status>OFF</Status>
174   - * 遇到过NVR下的IPC下发信令可以推流, 但是 Status 响应 OFF
175   - */
176   - @ApiModelProperty("状态")
177   - @Column(name="ONLINE")
178   - private String online;
179   -
180   - /**
181   - * 经度
182   - */
183   - @ApiModelProperty("经度")
184   - @Column(name="LONGITUDE")
185   - private double longitude;
186   -
187   - /**
188   - * 纬度
189   - */
190   - @ApiModelProperty("纬度")
191   - @Column(name="LATITUDE")
192   - private double latitude;
193   -
194   - public String getChannelId() {
195   - return channelId;
196   - }
197   -
198   - public void setChannelId(String channelId) {
199   - this.channelId = channelId;
200   - }
201   -
202   - public String getDeviceId() {
203   - return deviceId;
204   - }
205   -
206   - public void setDeviceId(String deviceId) {
207   - this.deviceId = deviceId;
208   - }
209   -
210   - public String getChannelName() {
211   - return channelName;
212   - }
213   -
214   - public void setChannelName(String channelName) {
215   - this.channelName = channelName;
216   - }
217   -
218   - public String getManufacture() {
219   - return manufacture;
220   - }
221   -
222   - public void setManufacture(String manufacture) {
223   - this.manufacture = manufacture;
224   - }
225   -
226   - public String getModel() {
227   - return model;
228   - }
229   -
230   - public void setModel(String model) {
231   - this.model = model;
232   - }
233   -
234   - public String getOwner() {
235   - return owner;
236   - }
237   -
238   - public void setOwner(String owner) {
239   - this.owner = owner;
240   - }
241   -
242   - public String getCivilCode() {
243   - return civilCode;
244   - }
245   -
246   - public void setCivilCode(String civilCode) {
247   - this.civilCode = civilCode;
248   - }
249   -
250   - public String getBlock() {
251   - return block;
252   - }
253   -
254   - public void setBlock(String block) {
255   - this.block = block;
256   - }
257   -
258   - public String getAddress() {
259   - return address;
260   - }
261   -
262   - public void setAddress(String address) {
263   - this.address = address;
264   - }
265   -
266   - public String getParental() {
267   - return parental;
268   - }
269   -
270   - public void setParental(String parental) {
271   - this.parental = parental;
272   - }
273   -
274   - public String getParentId() {
275   - return parentId;
276   - }
277   -
278   - public void setParentId(String parentId) {
279   - this.parentId = parentId;
280   - }
281   -
282   - public String getSafetyWay() {
283   - return safetyWay;
284   - }
285   -
286   - public void setSafetyWay(String safetyWay) {
287   - this.safetyWay = safetyWay;
288   - }
289   -
290   - public String getRegisterWay() {
291   - return registerWay;
292   - }
293   -
294   - public void setRegisterWay(String registerWay) {
295   - this.registerWay = registerWay;
296   - }
297   -
298   - public String getCertNum() {
299   - return certNum;
300   - }
301   -
302   - public void setCertNum(String certNum) {
303   - this.certNum = certNum;
304   - }
305   -
306   - public String getCertValid() {
307   - return certValid;
308   - }
309   -
310   - public void setCertValid(String certValid) {
311   - this.certValid = certValid;
312   - }
313   -
314   - public String getCertErrCode() {
315   - return certErrCode;
316   - }
317   -
318   - public void setCertErrCode(String certErrCode) {
319   - this.certErrCode = certErrCode;
320   - }
321   -
322   - public String getCertEndTime() {
323   - return certEndTime;
324   - }
325   -
326   - public void setCertEndTime(String certEndTime) {
327   - this.certEndTime = certEndTime;
328   - }
329   -
330   - public String getSecrecy() {
331   - return secrecy;
332   - }
333   -
334   - public void setSecrecy(String secrecy) {
335   - this.secrecy = secrecy;
336   - }
337   -
338   - public String getIp() {
339   - return ip;
340   - }
341   -
342   - public void setIp(String ip) {
343   - this.ip = ip;
344   - }
345   -
346   - public Integer getPort() {
347   - return port;
348   - }
349   -
350   - public void setPort(Integer port) {
351   - this.port = port;
352   - }
353   -
354   - public String getPassword() {
355   - return password;
356   - }
357   -
358   - public void setPassword(String password) {
359   - this.password = password;
360   - }
361   -
362   - public String getOnline() {
363   - return online;
364   - }
365   -
366   - public void setOnline(String online) {
367   - this.online = online;
368   - }
369   -
370   - public double getLongitude() {
371   - return longitude;
372   - }
373   -
374   - public void setLongitude(double longitude) {
375   - this.longitude = longitude;
376   - }
377   -
378   - public double getLatitude() {
379   - return latitude;
380   - }
381   -
382   - public void setLatitude(double latitude) {
383   - this.latitude = latitude;
384   - }
385   -}
src/main/java/com/genersoft/iot/vmp/vmanager/play/PlayController.java
... ... @@ -7,6 +7,8 @@ import com.genersoft.iot.vmp.conf.MediaServerConfig;
7 7 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
8 8 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
9 9 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  10 +import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
  11 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
10 12 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
11 13 import org.slf4j.Logger;
12 14 import org.slf4j.LoggerFactory;
... ... @@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
27 29 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
28 30 import org.springframework.web.context.request.async.DeferredResult;
29 31  
  32 +import javax.sip.message.Response;
30 33 import java.text.DecimalFormat;
31 34 import java.util.UUID;
32 35  
... ... @@ -44,6 +47,9 @@ public class PlayController {
44 47 private IVideoManagerStorager storager;
45 48  
46 49 @Autowired
  50 + private IRedisCatchStorage redisCatchStorage;
  51 +
  52 + @Autowired
47 53 private ZLMRESTfulUtils zlmresTfulUtils;
48 54  
49 55 @Autowired
... ... @@ -58,18 +64,11 @@ public class PlayController {
58 64  
59 65  
60 66 Device device = storager.queryVideoDevice(deviceId);
61   - StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId);
  67 + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId);
62 68  
63 69 UUID uuid = UUID.randomUUID();
64 70 DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
65   - // 超时处理
66   - result.onTimeout(()->{
67   - logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
68   - RequestMessage msg = new RequestMessage();
69   - msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
70   - msg.setData("Timeout");
71   - resultHolder.invokeResult(msg);
72   - });
  71 +
73 72 // 录像查询以channelId作为deviceId查询
74 73 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
75 74  
... ... @@ -78,9 +77,15 @@ public class PlayController {
78 77 cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
79 78 logger.info("收到订阅消息: " + response.toJSONString());
80 79 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  80 + }, event -> {
  81 + RequestMessage msg = new RequestMessage();
  82 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  83 + Response response = event.getResponse();
  84 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  85 + resultHolder.invokeResult(msg);
81 86 });
82 87 } else {
83   - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase();
  88 + String streamId = streamInfo.getStreamId();
84 89 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
85 90 if (rtpInfo.getBoolean("exist")) {
86 91 RequestMessage msg = new RequestMessage();
... ... @@ -88,58 +93,107 @@ public class PlayController {
88 93 msg.setData(JSON.toJSONString(streamInfo));
89 94 resultHolder.invokeResult(msg);
90 95 } else {
91   - storager.stopPlay(streamInfo);
92   - // TODO playStreamCmd 超时处理
  96 + redisCatchStorage.stopPlay(streamInfo);
93 97 cmder.playStreamCmd(device, channelId, (JSONObject response) -> {
94 98 logger.info("收到订阅消息: " + response.toJSONString());
95 99 playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString());
  100 + }, event -> {
  101 + RequestMessage msg = new RequestMessage();
  102 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  103 + Response response = event.getResponse();
  104 + msg.setData(String.format("点播失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  105 + resultHolder.invokeResult(msg);
96 106 });
97 107 }
98 108 }
  109 +
  110 + // 超时处理
  111 + result.onTimeout(()->{
  112 + logger.warn(String.format("设备点播超时,deviceId:%s ,channelId:%s", deviceId, channelId));
  113 + // 释放rtpserver
  114 + cmder.closeRTPServer(device, channelId);
  115 + RequestMessage msg = new RequestMessage();
  116 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  117 + msg.setData("Timeout");
  118 + resultHolder.invokeResult(msg);
  119 + });
99 120 return result;
100 121 }
101 122  
102   - @PostMapping("/play/{ssrc}/stop")
103   - public ResponseEntity<String> playStop(@PathVariable String ssrc) {
  123 + @PostMapping("/play/{streamId}/stop")
  124 + public DeferredResult<ResponseEntity<String>> playStop(@PathVariable String streamId) {
104 125  
105   - cmder.streamByeCmd(ssrc);
106   - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
107   - if (streamInfo == null)
108   - return new ResponseEntity<String>("ssrc not found", HttpStatus.OK);
109   - storager.stopPlay(streamInfo);
110   - if (logger.isDebugEnabled()) {
111   - logger.debug(String.format("设备预览停止API调用,ssrc:%s", ssrc));
112   - }
  126 + logger.debug(String.format("设备预览/回放停止API调用,streamId:%s", streamId));
  127 +
  128 + UUID uuid = UUID.randomUUID();
  129 + DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>();
113 130  
114   - if (ssrc != null) {
  131 + // 录像查询以channelId作为deviceId查询
  132 + resultHolder.put(DeferredResultHolder.CALLBACK_CMD_STOP + uuid, result);
  133 +
  134 + cmder.streamByeCmd(streamId, event -> {
  135 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
  136 + if (streamInfo == null) {
  137 + RequestMessage msg = new RequestMessage();
  138 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  139 + msg.setData("streamId not found");
  140 + resultHolder.invokeResult(msg);
  141 + redisCatchStorage.stopPlay(streamInfo);
  142 + }
  143 +
  144 + RequestMessage msg = new RequestMessage();
  145 + msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
  146 + Response response = event.getResponse();
  147 + msg.setData(String.format("success"));
  148 + resultHolder.invokeResult(msg);
  149 + });
  150 +
  151 +
  152 +
  153 + if (streamId != null) {
115 154 JSONObject json = new JSONObject();
116   - json.put("ssrc", ssrc);
117   - return new ResponseEntity<String>(json.toString(), HttpStatus.OK);
  155 + json.put("streamId", streamId);
  156 + RequestMessage msg = new RequestMessage();
  157 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  158 + msg.setData(json.toString());
  159 + resultHolder.invokeResult(msg);
118 160 } else {
119   - logger.warn("设备预览停止API调用失败!");
120   - return new ResponseEntity<String>(HttpStatus.INTERNAL_SERVER_ERROR);
  161 + logger.warn("设备预览/回放停止API调用失败!");
  162 + RequestMessage msg = new RequestMessage();
  163 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  164 + msg.setData("streamId null");
  165 + resultHolder.invokeResult(msg);
121 166 }
  167 +
  168 + // 超时处理
  169 + result.onTimeout(()->{
  170 + logger.warn(String.format("设备预览/回放停止超时,streamId:%s ", streamId));
  171 + RequestMessage msg = new RequestMessage();
  172 + msg.setId(DeferredResultHolder.CALLBACK_CMD_STOP + uuid);
  173 + msg.setData("Timeout");
  174 + resultHolder.invokeResult(msg);
  175 + });
  176 + return result;
122 177 }
123 178  
124 179 /**
125 180 * 将不是h264的视频通过ffmpeg 转码为h264 + aac
126   - * @param ssrc
  181 + * @param streamId 流ID
127 182 * @return
128 183 */
129   - @PostMapping("/play/{ssrc}/convert")
130   - public ResponseEntity<String> playConvert(@PathVariable String ssrc) {
131   - StreamInfo streamInfo = storager.queryPlayBySSRC(ssrc);
  184 + @PostMapping("/play/{streamId}/convert")
  185 + public ResponseEntity<String> playConvert(@PathVariable String streamId) {
  186 + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId);
132 187 if (streamInfo == null) {
133 188 logger.warn("视频转码API调用失败!, 视频流已经停止!");
134 189 return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK);
135 190 }
136   - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase();
137 191 JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId);
138 192 if (!rtpInfo.getBoolean("exist")) {
139 193 logger.warn("视频转码API调用失败!, 视频流已停止推流!");
140 194 return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK);
141 195 } else {
142   - MediaServerConfig mediaInfo = storager.getMediaInfo();
  196 + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo();
143 197 String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(),
144 198 streamId );
145 199 String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId);
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/playback/PlaybackController.java
... ... @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo;
6 6 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
7 7 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
8 8 import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils;
  9 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 10 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
10 11 import org.slf4j.Logger;
11 12 import org.slf4j.LoggerFactory;
... ... @@ -27,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
27 28 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
28 29 import org.springframework.web.context.request.async.DeferredResult;
29 30  
  31 +import javax.sip.message.Response;
30 32 import java.util.UUID;
31 33  
32 34 @CrossOrigin
... ... @@ -43,6 +45,9 @@ public class PlaybackController {
43 45 private IVideoManagerStorager storager;
44 46  
45 47 @Autowired
  48 + private IRedisCatchStorage redisCatchStorage;
  49 +
  50 + @Autowired
46 51 private ZLMRESTfulUtils zlmresTfulUtils;
47 52  
48 53 @Autowired
... ... @@ -69,15 +74,21 @@ public class PlaybackController {
69 74 resultHolder.invokeResult(msg);
70 75 });
71 76 Device device = storager.queryVideoDevice(deviceId);
72   - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId);
  77 + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId);
73 78 if (streamInfo != null) {
74 79 // 停止之前的回放
75   - cmder.streamByeCmd(streamInfo.getSsrc());
  80 + cmder.streamByeCmd(streamInfo.getStreamId());
76 81 }
77 82 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result);
78 83 cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> {
79 84 logger.info("收到订阅消息: " + response.toJSONString());
80 85 playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString());
  86 + }, event -> {
  87 + Response response = event.getResponse();
  88 + RequestMessage msg = new RequestMessage();
  89 + msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
  90 + msg.setData(String.format("回放失败, 错误码: %s, %s", response.getStatusCode(), response.getReasonPhrase()));
  91 + resultHolder.invokeResult(msg);
81 92 });
82 93  
83 94 return result;
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
... ... @@ -29,15 +29,14 @@ public class PtzController {
29 29 private IVideoManagerStorager storager;
30 30  
31 31 /***
32   - * http://localhost:8080/api/ptz/34020000001320000002_34020000001320000008?leftRight=1&upDown=0&inOut=0&moveSpeed=50&zoomSpeed=0
33   - * @param deviceId
34   - * @param channelId
35   - * @param leftRight
36   - * @param upDown
37   - * @param inOut
38   - * @param moveSpeed
39   - * @param zoomSpeed
40   - * @return
  32 + * 云台控制
  33 + * @param deviceId 设备id
  34 + * @param channelId 通道id
  35 + * @param cmdCode 指令码
  36 + * @param horizonSpeed 水平移动速度
  37 + * @param verticalSpeed 垂直移动速度
  38 + * @param zoomSpeed 缩放速度
  39 + * @return String 控制结果
41 40 */
42 41 @PostMapping("/ptz/{deviceId}/{channelId}")
43 42 public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed){
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java
1 1 package com.genersoft.iot.vmp.vmanager.record;
2 2  
  3 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
3 4 import org.slf4j.Logger;
4 5 import org.slf4j.LoggerFactory;
5 6 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -32,7 +33,7 @@ public class RecordController {
32 33  
33 34 @Autowired
34 35 private DeferredResultHolder resultHolder;
35   -
  36 +
36 37 @GetMapping("/record/{deviceId}/{channelId}")
37 38 public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){
38 39  
... ... @@ -42,9 +43,17 @@ public class RecordController {
42 43  
43 44 Device device = storager.queryVideoDevice(deviceId);
44 45 cmder.recordInfoQuery(device, channelId, startTime, endTime);
45   - DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>();
  46 + // 指定超时时间 1分钟30秒
  47 + DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<ResponseEntity<RecordInfo>>(90*1000L);
46 48 // 录像查询以channelId作为deviceId查询
47 49 resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result);
  50 + result.onTimeout(()->{
  51 + RequestMessage msg = new RequestMessage();
  52 + msg.setDeviceId(deviceId);
  53 + msg.setType(DeferredResultHolder.CALLBACK_CMD_RECORDINFO);
  54 + msg.setData("timeout");
  55 + resultHolder.invokeResult(msg);
  56 + });
48 57 return result;
49 58 }
50 59 }
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/service/impl/PlayServiceImpl.java
... ... @@ -4,8 +4,10 @@ import com.alibaba.fastjson.JSON;
4 4 import com.alibaba.fastjson.JSONObject;
5 5 import com.genersoft.iot.vmp.common.StreamInfo;
6 6 import com.genersoft.iot.vmp.conf.MediaServerConfig;
  7 +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
7 8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
8 9 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  10 +import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
9 11 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
10 12 import com.genersoft.iot.vmp.vmanager.play.PlayController;
11 13 import com.genersoft.iot.vmp.vmanager.service.IPlayService;
... ... @@ -25,6 +27,9 @@ public class PlayServiceImpl implements IPlayService {
25 27 private IVideoManagerStorager storager;
26 28  
27 29 @Autowired
  30 + private IRedisCatchStorage redisCatchStorage;
  31 +
  32 + @Autowired
28 33 private DeferredResultHolder resultHolder;
29 34  
30 35 @Override
... ... @@ -33,7 +38,13 @@ public class PlayServiceImpl implements IPlayService {
33 38 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
34 39 StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
35 40 if (streamInfo != null) {
36   - storager.startPlay(streamInfo);
  41 + DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId);
  42 + if (deviceChannel != null) {
  43 + deviceChannel.setStreamId(streamInfo.getStreamId());
  44 + storager.updateChannel(deviceId, deviceChannel);
  45 + }
  46 +
  47 + redisCatchStorage.startPlay(streamInfo);
37 48 msg.setData(JSON.toJSONString(streamInfo));
38 49 resultHolder.invokeResult(msg);
39 50 } else {
... ... @@ -49,7 +60,7 @@ public class PlayServiceImpl implements IPlayService {
49 60 msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid);
50 61 StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid);
51 62 if (streamInfo != null) {
52   - storager.startPlayback(streamInfo);
  63 + redisCatchStorage.startPlayback(streamInfo);
53 64 msg.setData(JSON.toJSONString(streamInfo));
54 65 resultHolder.invokeResult(msg);
55 66 } else {
... ... @@ -61,13 +72,11 @@ public class PlayServiceImpl implements IPlayService {
61 72  
62 73 public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) {
63 74 String streamId = resonse.getString("id");
64   - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16));
65 75 StreamInfo streamInfo = new StreamInfo();
66   - streamInfo.setSsrc(ssrc);
67 76 streamInfo.setStreamId(streamId);
68 77 streamInfo.setDeviceID(deviceId);
69 78 streamInfo.setCahnnelId(channelId);
70   - MediaServerConfig mediaServerConfig = storager.getMediaInfo();
  79 + MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo();
71 80  
72 81 streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
73 82 streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId));
... ...
src/main/java/com/genersoft/iot/vmp/web/ApiDeviceController.java
1 1 package com.genersoft.iot.vmp.web;
2 2  
3   -import com.alibaba.fastjson.JSON;
4 3 import com.alibaba.fastjson.JSONArray;
5 4 import com.alibaba.fastjson.JSONObject;
6   -import com.genersoft.iot.vmp.common.PageResult;
7 5 import com.genersoft.iot.vmp.gb28181.bean.Device;
8 6 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
9 7 import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector;
10 8 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
11 9 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
12 10 import com.genersoft.iot.vmp.storager.IVideoManagerStorager;
13   -import com.genersoft.iot.vmp.vmanager.device.DeviceController;
  11 +import com.github.pagehelper.PageInfo;
14 12 import org.slf4j.Logger;
15 13 import org.slf4j.LoggerFactory;
16 14 import org.springframework.beans.factory.annotation.Autowired;
17   -import org.springframework.http.HttpStatus;
18   -import org.springframework.http.ResponseEntity;
19   -import org.springframework.stereotype.Controller;
20 15 import org.springframework.web.bind.annotation.*;
21 16  
22 17 import java.util.List;
... ... @@ -65,12 +60,12 @@ public class ApiDeviceController {
65 60 JSONObject result = new JSONObject();
66 61 List<Device> devices;
67 62 if (start == null || limit ==null) {
68   - devices = storager.queryVideoDeviceList(null);
  63 + devices = storager.queryVideoDeviceList();
69 64 result.put("DeviceCount", devices.size());
70 65 }else {
71   - PageResult<Device> deviceList = storager.queryVideoDeviceList(null, start/limit, limit);
  66 + PageInfo<Device> deviceList = storager.queryVideoDeviceList(start/limit, limit);
72 67 result.put("DeviceCount", deviceList.getTotal());
73   - devices = deviceList.getData();
  68 + devices = deviceList.getList();
74 69 }
75 70  
76 71 JSONArray deviceJSONList = new JSONArray();
... ... @@ -86,8 +81,8 @@ public class ApiDeviceController {
86 81 deviceJsonObject.put("Online", device.getOnline() == 1);
87 82 deviceJsonObject.put("Password", "");
88 83 deviceJsonObject.put("MediaTransport", device.getTransport());
89   - deviceJsonObject.put("RemoteIP", device.getHost().getIp());
90   - deviceJsonObject.put("RemotePort", device.getHost().getPort());
  84 + deviceJsonObject.put("RemoteIP", device.getIp());
  85 + deviceJsonObject.put("RemotePort", device.getPort());
91 86 deviceJsonObject.put("LastRegisterAt", "");
92 87 deviceJsonObject.put("LastKeepaliveAt", "");
93 88 deviceJsonObject.put("UpdatedAt", "");
... ... @@ -123,9 +118,9 @@ public class ApiDeviceController {
123 118 deviceChannels = storager.queryChannelsByDeviceId(serial);
124 119 result.put("ChannelCount", deviceChannels.size());
125 120 }else {
126   - PageResult<DeviceChannel> pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit);
  121 + PageInfo<DeviceChannel> pageResult = storager.queryChannelsByDeviceId(serial, null, null, null,start/limit, limit);
127 122 result.put("ChannelCount", pageResult.getTotal());
128   - deviceChannels = pageResult.getData();
  123 + deviceChannels = pageResult.getList();
129 124 }
130 125  
131 126 JSONArray channleJSONList = new JSONArray();
... ... @@ -159,7 +154,7 @@ public class ApiDeviceController {
159 154 deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球,
160 155 // 3 - 固定枪机, 4 - 遥控枪机
161 156 deviceJOSNChannel.put("CustomPTZType", "");
162   - deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播
  157 + deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播
163 158 deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数
164 159 channleJSONList.add(deviceJOSNChannel);
165 160 }
... ...