Commit 34135cce5d59f6ad7653737dd035bb1d441e185f
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
49 changed files
with
1567 additions
and
2360 deletions
pom.xml
| @@ -13,13 +13,38 @@ | @@ -13,13 +13,38 @@ | ||
| 13 | <artifactId>wvp</artifactId> | 13 | <artifactId>wvp</artifactId> |
| 14 | <name>web video platform</name> | 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 | <properties> | 44 | <properties> |
| 17 | <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> | 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 | <pagehelper.version>5.2.0</pagehelper.version> | 48 | <pagehelper.version>5.2.0</pagehelper.version> |
| 24 | <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory> | 49 | <snippetsDirectory>${project.build.directory}/generated-snippets</snippetsDirectory> |
| 25 | <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory> | 50 | <asciidoctor.input.directory>${project.basedir}/docs/asciidoc</asciidoctor.input.directory> |
| @@ -31,30 +56,16 @@ | @@ -31,30 +56,16 @@ | ||
| 31 | <dependencies> | 56 | <dependencies> |
| 32 | <dependency> | 57 | <dependency> |
| 33 | <groupId>org.springframework.boot</groupId> | 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 | </dependency> | 60 | </dependency> |
| 40 | <dependency> | 61 | <dependency> |
| 41 | <groupId>org.springframework.boot</groupId> | 62 | <groupId>org.springframework.boot</groupId> |
| 42 | <artifactId>spring-boot-starter-web</artifactId> | 63 | <artifactId>spring-boot-starter-web</artifactId> |
| 43 | </dependency> | 64 | </dependency> |
| 44 | <dependency> | 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 | </dependency> | 69 | </dependency> |
| 59 | 70 | ||
| 60 | <!-- druid数据库连接池 --> | 71 | <!-- druid数据库连接池 --> |
| @@ -71,36 +82,25 @@ | @@ -71,36 +82,25 @@ | ||
| 71 | <version>8.0.22</version> | 82 | <version>8.0.22</version> |
| 72 | </dependency> | 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 | <dependency> | 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 | </dependency> | 90 | </dependency> |
| 85 | 91 | ||
| 86 | - <!--分页插件 --> | 92 | + <!--Mybatis分页插件 --> |
| 87 | <dependency> | 93 | <dependency> |
| 88 | <groupId>com.github.pagehelper</groupId> | 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 | </dependency> | 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 | <!--Swagger2 --> | 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,7 +4,6 @@ import com.alibaba.fastjson.JSONArray; | ||
| 4 | 4 | ||
| 5 | public class StreamInfo { | 5 | public class StreamInfo { |
| 6 | 6 | ||
| 7 | - private String ssrc; | ||
| 8 | private String streamId; | 7 | private String streamId; |
| 9 | private String deviceID; | 8 | private String deviceID; |
| 10 | private String cahnnelId; | 9 | private String cahnnelId; |
| @@ -20,14 +19,6 @@ public class StreamInfo { | @@ -20,14 +19,6 @@ public class StreamInfo { | ||
| 20 | private String rtsp; | 19 | private String rtsp; |
| 21 | private JSONArray tracks; | 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 | public String getDeviceID() { | 22 | public String getDeviceID() { |
| 32 | return deviceID; | 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 +8,10 @@ import java.util.concurrent.ThreadPoolExecutor; | ||
| 8 | import java.util.concurrent.TimeUnit; | 8 | import java.util.concurrent.TimeUnit; |
| 9 | 9 | ||
| 10 | import javax.sip.*; | 10 | import javax.sip.*; |
| 11 | +import javax.sip.header.CallIdHeader; | ||
| 11 | import javax.sip.message.Response; | 12 | import javax.sip.message.Response; |
| 12 | 13 | ||
| 14 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | ||
| 13 | import org.slf4j.Logger; | 15 | import org.slf4j.Logger; |
| 14 | import org.slf4j.LoggerFactory; | 16 | import org.slf4j.LoggerFactory; |
| 15 | import org.springframework.beans.factory.annotation.Autowired; | 17 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -34,6 +36,9 @@ public class SipLayer implements SipListener { | @@ -34,6 +36,9 @@ public class SipLayer implements SipListener { | ||
| 34 | @Autowired | 36 | @Autowired |
| 35 | private SIPProcessorFactory processorFactory; | 37 | private SIPProcessorFactory processorFactory; |
| 36 | 38 | ||
| 39 | + @Autowired | ||
| 40 | + private SipSubscribe sipSubscribe; | ||
| 41 | + | ||
| 37 | private SipStack sipStack; | 42 | private SipStack sipStack; |
| 38 | 43 | ||
| 39 | private SipFactory sipFactory; | 44 | private SipFactory sipFactory; |
| @@ -133,17 +138,34 @@ public class SipLayer implements SipListener { | @@ -133,17 +138,34 @@ public class SipLayer implements SipListener { | ||
| 133 | // TODO Auto-generated catch block | 138 | // TODO Auto-generated catch block |
| 134 | e.printStackTrace(); | 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 | // } else if (status == Response.TRYING) { | 150 | // } else if (status == Response.TRYING) { |
| 137 | // trying不会回复 | 151 | // trying不会回复 |
| 138 | } else if ((status >= 100) && (status < 200)) { | 152 | } else if ((status >= 100) && (status < 200)) { |
| 139 | // 增加其它无需回复的响应,如101、180等 | 153 | // 增加其它无需回复的响应,如101、180等 |
| 140 | } else { | 154 | } else { |
| 141 | logger.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()/* .getContent().toString()*/); | 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,6 +27,7 @@ package com.genersoft.iot.vmp.gb28181.auth; | ||
| 27 | 27 | ||
| 28 | import java.security.MessageDigest; | 28 | import java.security.MessageDigest; |
| 29 | import java.security.NoSuchAlgorithmException; | 29 | import java.security.NoSuchAlgorithmException; |
| 30 | +import java.text.DecimalFormat; | ||
| 30 | import java.util.Date; | 31 | import java.util.Date; |
| 31 | import java.util.Random; | 32 | import java.util.Random; |
| 32 | 33 | ||
| @@ -103,9 +104,12 @@ public class DigestServerAuthenticationHelper { | @@ -103,9 +104,12 @@ public class DigestServerAuthenticationHelper { | ||
| 103 | .createWWWAuthenticateHeader(DEFAULT_SCHEME); | 104 | .createWWWAuthenticateHeader(DEFAULT_SCHEME); |
| 104 | proxyAuthenticate.setParameter("realm", realm); | 105 | proxyAuthenticate.setParameter("realm", realm); |
| 105 | proxyAuthenticate.setParameter("nonce", generateNonce()); | 106 | proxyAuthenticate.setParameter("nonce", generateNonce()); |
| 107 | + | ||
| 106 | proxyAuthenticate.setParameter("opaque", ""); | 108 | proxyAuthenticate.setParameter("opaque", ""); |
| 107 | proxyAuthenticate.setParameter("stale", "FALSE"); | 109 | proxyAuthenticate.setParameter("stale", "FALSE"); |
| 108 | proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM); | 110 | proxyAuthenticate.setParameter("algorithm", DEFAULT_ALGORITHM); |
| 111 | + | ||
| 112 | +// proxyAuthenticate.setParameter("qop", "auth"); | ||
| 109 | response.setHeader(proxyAuthenticate); | 113 | response.setHeader(proxyAuthenticate); |
| 110 | } catch (Exception ex) { | 114 | } catch (Exception ex) { |
| 111 | InternalErrorHandler.handleException(ex); | 115 | InternalErrorHandler.handleException(ex); |
| @@ -170,42 +174,116 @@ public class DigestServerAuthenticationHelper { | @@ -170,42 +174,116 @@ public class DigestServerAuthenticationHelper { | ||
| 170 | public boolean doAuthenticatePlainTextPassword(Request request, String pass) { | 174 | public boolean doAuthenticatePlainTextPassword(Request request, String pass) { |
| 171 | AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); | 175 | AuthorizationHeader authHeader = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); |
| 172 | if ( authHeader == null ) return false; | 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 | if ( username == null || realm == null ) { | 180 | if ( username == null || realm == null ) { |
| 178 | return false; | 181 | return false; |
| 179 | } | 182 | } |
| 180 | - | ||
| 181 | 183 | ||
| 182 | String nonce = authHeader.getNonce(); | 184 | String nonce = authHeader.getNonce(); |
| 183 | URI uri = authHeader.getURI(); | 185 | URI uri = authHeader.getURI(); |
| 184 | if (uri == null) { | 186 | if (uri == null) { |
| 185 | return false; | 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 | String A1 = username + ":" + realm + ":" + pass; | 201 | String A1 = username + ":" + realm + ":" + pass; |
| 190 | String A2 = request.getMethod().toUpperCase() + ":" + uri.toString(); | 202 | String A2 = request.getMethod().toUpperCase() + ":" + uri.toString(); |
| 191 | byte mdbytes[] = messageDigest.digest(A1.getBytes()); | 203 | byte mdbytes[] = messageDigest.digest(A1.getBytes()); |
| 192 | String HA1 = toHexString(mdbytes); | 204 | String HA1 = toHexString(mdbytes); |
| 205 | + System.out.println("A1: " + A1); | ||
| 206 | + System.out.println("A2: " + A2); | ||
| 193 | 207 | ||
| 194 | - | ||
| 195 | mdbytes = messageDigest.digest(A2.getBytes()); | 208 | mdbytes = messageDigest.digest(A2.getBytes()); |
| 196 | String HA2 = toHexString(mdbytes); | 209 | String HA2 = toHexString(mdbytes); |
| 197 | - | 210 | + System.out.println("HA1: " + HA1); |
| 211 | + System.out.println("HA2: " + HA2); | ||
| 198 | String cnonce = authHeader.getCNonce(); | 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 | String KD = HA1 + ":" + nonce; | 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 | KD += ":" + HA2; | 228 | KD += ":" + HA2; |
| 229 | + System.out.println("KD: " + KD); | ||
| 204 | mdbytes = messageDigest.digest(KD.getBytes()); | 230 | mdbytes = messageDigest.digest(KD.getBytes()); |
| 205 | String mdString = toHexString(mdbytes); | 231 | String mdString = toHexString(mdbytes); |
| 232 | + System.out.println("mdString: " + mdString); | ||
| 206 | String response = authHeader.getResponse(); | 233 | String response = authHeader.getResponse(); |
| 234 | + System.out.println("response: " + response); | ||
| 207 | return mdString.equals(response); | 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,6 +21,6 @@ public class RegisterLogicHandler { | ||
| 21 | // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口 | 21 | // TODO 后续处理,只有第一次注册时调用查询设备信息,如需更新调用更新API接口 |
| 22 | cmder.deviceInfoQuery(device); | 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 | package com.genersoft.iot.vmp.gb28181.bean; | 1 | package com.genersoft.iot.vmp.gb28181.bean; |
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | -import java.util.List; | ||
| 5 | -import java.util.Map; | ||
| 6 | - | ||
| 7 | public class Device { | 4 | public class Device { |
| 8 | 5 | ||
| 9 | /** | 6 | /** |
| @@ -46,24 +43,36 @@ public class Device { | @@ -46,24 +43,36 @@ public class Device { | ||
| 46 | private String streamMode; | 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 | * wan地址 | 56 | * wan地址 |
| 50 | */ | 57 | */ |
| 51 | - private Host host; | 58 | + private String hostAddress; |
| 52 | 59 | ||
| 53 | /** | 60 | /** |
| 54 | * 在线 | 61 | * 在线 |
| 55 | */ | 62 | */ |
| 56 | private int online; | 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 | private int channelCount; | 74 | private int channelCount; |
| 64 | 75 | ||
| 65 | - private List<String> channelList; | ||
| 66 | - | ||
| 67 | public String getDeviceId() { | 76 | public String getDeviceId() { |
| 68 | return deviceId; | 77 | return deviceId; |
| 69 | } | 78 | } |
| @@ -120,12 +129,28 @@ public class Device { | @@ -120,12 +129,28 @@ public class Device { | ||
| 120 | this.streamMode = streamMode; | 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 | public int getOnline() { | 156 | public int getOnline() { |
| @@ -144,11 +169,11 @@ public class Device { | @@ -144,11 +169,11 @@ public class Device { | ||
| 144 | this.channelCount = channelCount; | 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,10 +2,17 @@ package com.genersoft.iot.vmp.gb28181.bean; | ||
| 2 | 2 | ||
| 3 | public class DeviceChannel { | 3 | public class DeviceChannel { |
| 4 | 4 | ||
| 5 | + | ||
| 6 | + | ||
| 5 | /** | 7 | /** |
| 6 | * 通道id | 8 | * 通道id |
| 7 | */ | 9 | */ |
| 8 | private String channelId; | 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,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 | public void setPTZType(int PTZType) { | 166 | public void setPTZType(int PTZType) { |
| 158 | this.PTZType = PTZType; | 167 | this.PTZType = PTZType; |
| @@ -379,14 +388,6 @@ public class DeviceChannel { | @@ -379,14 +388,6 @@ public class DeviceChannel { | ||
| 379 | this.subCount = subCount; | 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 | public boolean isHasAudio() { | 391 | public boolean isHasAudio() { |
| 391 | return hasAudio; | 392 | return hasAudio; |
| 392 | } | 393 | } |
| @@ -395,11 +396,11 @@ public class DeviceChannel { | @@ -395,11 +396,11 @@ public class DeviceChannel { | ||
| 395 | this.hasAudio = hasAudio; | 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,8 +7,10 @@ import javax.sip.header.CSeqHeader; | ||
| 7 | import javax.sip.message.Request; | 7 | import javax.sip.message.Request; |
| 8 | import javax.sip.message.Response; | 8 | import javax.sip.message.Response; |
| 9 | 9 | ||
| 10 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 10 | import com.alibaba.fastjson.JSON; | 11 | import com.alibaba.fastjson.JSON; |
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; | 12 | import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; |
| 13 | +import com.genersoft.iot.vmp.gb28181.transmit.response.impl.*; | ||
| 12 | import org.slf4j.Logger; | 14 | import org.slf4j.Logger; |
| 13 | import org.slf4j.LoggerFactory; | 15 | import org.slf4j.LoggerFactory; |
| 14 | import org.springframework.beans.factory.annotation.Autowired; | 16 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -54,7 +56,10 @@ public class SIPProcessorFactory { | @@ -54,7 +56,10 @@ public class SIPProcessorFactory { | ||
| 54 | 56 | ||
| 55 | @Autowired | 57 | @Autowired |
| 56 | private IVideoManagerStorager storager; | 58 | private IVideoManagerStorager storager; |
| 57 | - | 59 | + |
| 60 | + @Autowired | ||
| 61 | + private IRedisCatchStorage redisCatchStorage; | ||
| 62 | + | ||
| 58 | @Autowired | 63 | @Autowired |
| 59 | private EventPublisher publisher; | 64 | private EventPublisher publisher; |
| 60 | 65 | ||
| @@ -82,10 +87,11 @@ public class SIPProcessorFactory { | @@ -82,10 +87,11 @@ public class SIPProcessorFactory { | ||
| 82 | @Autowired | 87 | @Autowired |
| 83 | @Lazy | 88 | @Lazy |
| 84 | private RegisterResponseProcessor registerResponseProcessor; | 89 | private RegisterResponseProcessor registerResponseProcessor; |
| 85 | - | 90 | + |
| 86 | @Autowired | 91 | @Autowired |
| 87 | private OtherResponseProcessor otherResponseProcessor; | 92 | private OtherResponseProcessor otherResponseProcessor; |
| 88 | - | 93 | + |
| 94 | + | ||
| 89 | // 注:这里使用注解会导致循环依赖注入,暂用springBean | 95 | // 注:这里使用注解会导致循环依赖注入,暂用springBean |
| 90 | private SipProvider tcpSipProvider; | 96 | private SipProvider tcpSipProvider; |
| 91 | 97 | ||
| @@ -140,6 +146,7 @@ public class SIPProcessorFactory { | @@ -140,6 +146,7 @@ public class SIPProcessorFactory { | ||
| 140 | processor.setOffLineDetector(offLineDetector); | 146 | processor.setOffLineDetector(offLineDetector); |
| 141 | processor.setCmder(cmder); | 147 | processor.setCmder(cmder); |
| 142 | processor.setStorager(storager); | 148 | processor.setStorager(storager); |
| 149 | + processor.setRedisCatchStorage(redisCatchStorage); | ||
| 143 | return processor; | 150 | return processor; |
| 144 | } else { | 151 | } else { |
| 145 | return new OtherRequestProcessor(); | 152 | return new OtherRequestProcessor(); |
| @@ -147,6 +154,7 @@ public class SIPProcessorFactory { | @@ -147,6 +154,7 @@ public class SIPProcessorFactory { | ||
| 147 | } | 154 | } |
| 148 | 155 | ||
| 149 | public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { | 156 | public ISIPResponseProcessor createResponseProcessor(ResponseEvent evt) { |
| 157 | + | ||
| 150 | Response response = evt.getResponse(); | 158 | Response response = evt.getResponse(); |
| 151 | CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); | 159 | CSeqHeader cseqHeader = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
| 152 | String method = cseqHeader.getMethod(); | 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,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.transmit.callback; | ||
| 2 | 2 | ||
| 3 | import java.util.HashMap; | 3 | import java.util.HashMap; |
| 4 | import java.util.Map; | 4 | import java.util.Map; |
| 5 | +import java.util.concurrent.ConcurrentHashMap; | ||
| 5 | 6 | ||
| 6 | import org.springframework.http.HttpStatus; | 7 | import org.springframework.http.HttpStatus; |
| 7 | import org.springframework.http.ResponseEntity; | 8 | import org.springframework.http.ResponseEntity; |
| @@ -24,8 +25,10 @@ public class DeferredResultHolder { | @@ -24,8 +25,10 @@ public class DeferredResultHolder { | ||
| 24 | 25 | ||
| 25 | public static final String CALLBACK_CMD_PlAY = "CALLBACK_PLAY"; | 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 | public void put(String key, DeferredResult result) { | 32 | public void put(String key, DeferredResult result) { |
| 30 | map.put(key, result); | 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,8 +2,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.cmd; | ||
| 2 | 2 | ||
| 3 | import com.genersoft.iot.vmp.common.StreamInfo; | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | ||
| 5 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; | 6 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; |
| 6 | -import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | ||
| 7 | 7 | ||
| 8 | /** | 8 | /** |
| 9 | * @Description:设备能力接口,用于定义设备的控制、查询能力 | 9 | * @Description:设备能力接口,用于定义设备的控制、查询能力 |
| @@ -84,7 +84,7 @@ public interface ISIPCommander { | @@ -84,7 +84,7 @@ public interface ISIPCommander { | ||
| 84 | * @param device 视频设备 | 84 | * @param device 视频设备 |
| 85 | * @param channelId 预览通道 | 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,15 +94,16 @@ public interface ISIPCommander { | ||
| 94 | * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss | 94 | * @param startTime 开始时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 95 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | 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 | * @param ssrc ssrc | 102 | * @param ssrc ssrc |
| 103 | */ | 103 | */ |
| 104 | + void streamByeCmd(String ssrc, SipSubscribe.Event okEvent); | ||
| 104 | void streamByeCmd(String ssrc); | 105 | void streamByeCmd(String ssrc); |
| 105 | - | 106 | + |
| 106 | /** | 107 | /** |
| 107 | * 语音广播 | 108 | * 语音广播 |
| 108 | * | 109 | * |
| @@ -176,7 +177,7 @@ public interface ISIPCommander { | @@ -176,7 +177,7 @@ public interface ISIPCommander { | ||
| 176 | * | 177 | * |
| 177 | * @param device 视频设备 | 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,4 +215,11 @@ public interface ISIPCommander { | ||
| 214 | * @param device 视频设备 | 215 | * @param device 视频设备 |
| 215 | */ | 216 | */ |
| 216 | boolean mobilePostitionQuery(Device device); | 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,9 +47,8 @@ public class SIPRequestHeaderProvider { | ||
| 47 | 47 | ||
| 48 | public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { | 48 | public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
| 49 | Request request = null; | 49 | Request request = null; |
| 50 | - Host host = device.getHost(); | ||
| 51 | // sipuri | 50 | // sipuri |
| 52 | - SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), host.getAddress()); | 51 | + SipURI requestURI = sipFactory.createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); |
| 53 | // via | 52 | // via |
| 54 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | 53 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 55 | ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), | 54 | ViaHeader viaHeader = sipFactory.createHeaderFactory().createViaHeader(sipConfig.getSipIp(), sipConfig.getSipPort(), |
| @@ -75,22 +74,21 @@ public class SIPRequestHeaderProvider { | @@ -75,22 +74,21 @@ public class SIPRequestHeaderProvider { | ||
| 75 | 74 | ||
| 76 | request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, | 75 | request = sipFactory.createMessageFactory().createRequest(requestURI, Request.MESSAGE, callIdHeader, cSeqHeader, fromHeader, |
| 77 | toHeader, viaHeaders, maxForwards); | 76 | toHeader, viaHeaders, maxForwards); |
| 78 | - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "MANSCDP+xml"); | 77 | + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "MANSCDP+xml"); |
| 79 | request.setContent(content, contentTypeHeader); | 78 | request.setContent(content, contentTypeHeader); |
| 80 | return request; | 79 | return request; |
| 81 | } | 80 | } |
| 82 | 81 | ||
| 83 | public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { | 82 | public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
| 84 | Request request = null; | 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 | //via | 86 | //via |
| 89 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | 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 | viaHeader.setRPort(); | 89 | viaHeader.setRPort(); |
| 93 | viaHeaders.add(viaHeader); | 90 | viaHeaders.add(viaHeader); |
| 91 | + | ||
| 94 | //from | 92 | //from |
| 95 | SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); | 93 | SipURI fromSipURI = sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(),sipConfig.getSipDomain()); |
| 96 | Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); | 94 | Address fromAddress = sipFactory.createAddressFactory().createAddress(fromSipURI); |
| @@ -122,20 +120,18 @@ public class SIPRequestHeaderProvider { | @@ -122,20 +120,18 @@ public class SIPRequestHeaderProvider { | ||
| 122 | // Subject | 120 | // Subject |
| 123 | SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0)); | 121 | SubjectHeader subjectHeader = sipFactory.createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", channelId, ssrc, sipConfig.getSipId(), 0)); |
| 124 | request.addHeader(subjectHeader); | 122 | request.addHeader(subjectHeader); |
| 125 | - ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("Application", "SDP"); | 123 | + ContentTypeHeader contentTypeHeader = sipFactory.createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP"); |
| 126 | request.setContent(content, contentTypeHeader); | 124 | request.setContent(content, contentTypeHeader); |
| 127 | return request; | 125 | return request; |
| 128 | } | 126 | } |
| 129 | 127 | ||
| 130 | public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { | 128 | public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag) throws ParseException, InvalidArgumentException, PeerUnavailableException { |
| 131 | Request request = null; | 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 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); | 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 | viaHeader.setRPort(); | 135 | viaHeader.setRPort(); |
| 140 | viaHeaders.add(viaHeader); | 136 | viaHeaders.add(viaHeader); |
| 141 | //from | 137 | //from |
| @@ -167,7 +163,7 @@ public class SIPRequestHeaderProvider { | @@ -167,7 +163,7 @@ public class SIPRequestHeaderProvider { | ||
| 167 | // Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort())); | 163 | // Address concatAddress = sipFactory.createAddressFactory().createAddress(sipFactory.createAddressFactory().createSipURI(sipConfig.getSipId(), device.getHost().getIp()+":"+device.getHost().getPort())); |
| 168 | request.addHeader(sipFactory.createHeaderFactory().createContactHeader(concatAddress)); | 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 | request.setContent(content, contentTypeHeader); | 167 | request.setContent(content, contentTypeHeader); |
| 172 | return request; | 168 | return request; |
| 173 | } | 169 | } |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| 1 | package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; | 1 | package com.genersoft.iot.vmp.gb28181.transmit.cmd.impl; |
| 2 | 2 | ||
| 3 | import java.text.ParseException; | 3 | import java.text.ParseException; |
| 4 | +import java.util.UUID; | ||
| 4 | import java.util.regex.Matcher; | 5 | import java.util.regex.Matcher; |
| 5 | import java.util.regex.Pattern; | 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 | import javax.sip.address.SipURI; | 9 | import javax.sip.address.SipURI; |
| 10 | +import javax.sip.header.CallIdHeader; | ||
| 11 | +import javax.sip.header.Header; | ||
| 15 | import javax.sip.header.ViaHeader; | 12 | import javax.sip.header.ViaHeader; |
| 16 | import javax.sip.message.Request; | 13 | import javax.sip.message.Request; |
| 17 | 14 | ||
| @@ -19,9 +16,13 @@ import com.alibaba.fastjson.JSONObject; | @@ -19,9 +16,13 @@ import com.alibaba.fastjson.JSONObject; | ||
| 19 | import com.genersoft.iot.vmp.common.StreamInfo; | 16 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 20 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 17 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 21 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 18 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 19 | +import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; | ||
| 22 | import com.genersoft.iot.vmp.media.zlm.ZLMHttpHookSubscribe; | 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 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 23 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 24 | +import org.slf4j.Logger; | ||
| 25 | +import org.slf4j.LoggerFactory; | ||
| 25 | import org.springframework.beans.factory.annotation.Autowired; | 26 | import org.springframework.beans.factory.annotation.Autowired; |
| 26 | import org.springframework.beans.factory.annotation.Qualifier; | 27 | import org.springframework.beans.factory.annotation.Qualifier; |
| 27 | import org.springframework.beans.factory.annotation.Value; | 28 | import org.springframework.beans.factory.annotation.Value; |
| @@ -41,6 +42,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; | @@ -41,6 +42,8 @@ import com.genersoft.iot.vmp.gb28181.utils.DateUtil; | ||
| 41 | */ | 42 | */ |
| 42 | @Component | 43 | @Component |
| 43 | public class SIPCommander implements ISIPCommander { | 44 | public class SIPCommander implements ISIPCommander { |
| 45 | + | ||
| 46 | + private final Logger logger = LoggerFactory.getLogger(SIPCommander.class); | ||
| 44 | 47 | ||
| 45 | @Autowired | 48 | @Autowired |
| 46 | private SipConfig sipConfig; | 49 | private SipConfig sipConfig; |
| @@ -53,6 +56,9 @@ public class SIPCommander implements ISIPCommander { | @@ -53,6 +56,9 @@ public class SIPCommander implements ISIPCommander { | ||
| 53 | 56 | ||
| 54 | @Autowired | 57 | @Autowired |
| 55 | private IVideoManagerStorager storager; | 58 | private IVideoManagerStorager storager; |
| 59 | + | ||
| 60 | + @Autowired | ||
| 61 | + private IRedisCatchStorage redisCatchStorage; | ||
| 56 | 62 | ||
| 57 | @Autowired | 63 | @Autowired |
| 58 | @Qualifier(value="tcpSipProvider") | 64 | @Qualifier(value="tcpSipProvider") |
| @@ -63,14 +69,20 @@ public class SIPCommander implements ISIPCommander { | @@ -63,14 +69,20 @@ public class SIPCommander implements ISIPCommander { | ||
| 63 | private SipProvider udpSipProvider; | 69 | private SipProvider udpSipProvider; |
| 64 | 70 | ||
| 65 | @Autowired | 71 | @Autowired |
| 66 | - private ZLMUtils zlmUtils; | 72 | + private ZLMRTPServerFactory zlmrtpServerFactory; |
| 67 | 73 | ||
| 68 | @Value("${media.rtp.enable}") | 74 | @Value("${media.rtp.enable}") |
| 69 | private boolean rtpEnable; | 75 | private boolean rtpEnable; |
| 70 | 76 | ||
| 77 | + @Value("${media.seniorSdp}") | ||
| 78 | + private boolean seniorSdp; | ||
| 79 | + | ||
| 71 | @Autowired | 80 | @Autowired |
| 72 | private ZLMHttpHookSubscribe subscribe; | 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,19 +188,29 @@ public class SIPCommander implements ISIPCommander { | ||
| 176 | * @param moveSpeed 镜头移动速度 默认 0XFF (0-255) | 188 | * @param moveSpeed 镜头移动速度 默认 0XFF (0-255) |
| 177 | * @param zoomSpeed 镜头缩放速度 默认 0X1 (0-255) | 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 | StringBuilder builder = new StringBuilder("A50F01"); | 202 | StringBuilder builder = new StringBuilder("A50F01"); |
| 181 | String strTmp; | 203 | String strTmp; |
| 182 | strTmp = String.format("%02X", cmdCode); | 204 | strTmp = String.format("%02X", cmdCode); |
| 183 | builder.append(strTmp, 0, 2); | 205 | builder.append(strTmp, 0, 2); |
| 184 | - strTmp = String.format("%02X", parameter1); | 206 | + strTmp = String.format("%02X", horizonSpeed); |
| 185 | builder.append(strTmp, 0, 2); | 207 | builder.append(strTmp, 0, 2); |
| 186 | - strTmp = String.format("%02X", parameter2); | 208 | + strTmp = String.format("%02X", verticalSpeed); |
| 187 | builder.append(strTmp, 0, 2); | 209 | builder.append(strTmp, 0, 2); |
| 188 | - strTmp = String.format("%X", combineCode2); | 210 | + strTmp = String.format("%X", zoomSpeed); |
| 189 | builder.append(strTmp, 0, 1).append("0"); | 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 | strTmp = String.format("%02X", checkCode); | 214 | strTmp = String.format("%02X", checkCode); |
| 193 | builder.append(strTmp, 0, 2); | 215 | builder.append(strTmp, 0, 2); |
| 194 | return builder.toString(); | 216 | return builder.toString(); |
| @@ -237,14 +259,14 @@ public class SIPCommander implements ISIPCommander { | @@ -237,14 +259,14 @@ public class SIPCommander implements ISIPCommander { | ||
| 237 | * @param device 控制设备 | 259 | * @param device 控制设备 |
| 238 | * @param channelId 预览通道 | 260 | * @param channelId 预览通道 |
| 239 | * @param cmdCode 指令码 | 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 | @Override | 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 | try { | 268 | try { |
| 247 | - String cmdStr= frontEndCmdString(cmdCode, parameter1, parameter2, combineCode2); | 269 | + String cmdStr= frontEndCmdString(cmdCode, horizonSpeed, verticalSpeed, zoomSpeed); |
| 248 | System.out.println("控制字符串:" + cmdStr); | 270 | System.out.println("控制字符串:" + cmdStr); |
| 249 | StringBuffer ptzXml = new StringBuffer(200); | 271 | StringBuffer ptzXml = new StringBuffer(200); |
| 250 | ptzXml.append("<?xml version=\"1.0\" ?>\r\n"); | 272 | ptzXml.append("<?xml version=\"1.0\" ?>\r\n"); |
| @@ -258,7 +280,6 @@ public class SIPCommander implements ISIPCommander { | @@ -258,7 +280,6 @@ public class SIPCommander implements ISIPCommander { | ||
| 258 | ptzXml.append("</Control>\r\n"); | 280 | ptzXml.append("</Control>\r\n"); |
| 259 | 281 | ||
| 260 | Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); | 282 | Request request = headerProvider.createMessageRequest(device, ptzXml.toString(), "ViaPtzBranch", "FromPtzTag", "ToPtzTag"); |
| 261 | - | ||
| 262 | transmitRequest(device, request); | 283 | transmitRequest(device, request); |
| 263 | return true; | 284 | return true; |
| 264 | } catch (SipException | ParseException | InvalidArgumentException e) { | 285 | } catch (SipException | ParseException | InvalidArgumentException e) { |
| @@ -266,28 +287,39 @@ public class SIPCommander implements ISIPCommander { | @@ -266,28 +287,39 @@ public class SIPCommander implements ISIPCommander { | ||
| 266 | } | 287 | } |
| 267 | return false; | 288 | return false; |
| 268 | } | 289 | } |
| 290 | + | ||
| 269 | /** | 291 | /** |
| 270 | - * 请求预览视频流 | ||
| 271 | - * | 292 | + * 请求预览视频流 |
| 272 | * @param device 视频设备 | 293 | * @param device 视频设备 |
| 273 | * @param channelId 预览通道 | 294 | * @param channelId 预览通道 |
| 295 | + * @param event hook订阅 | ||
| 296 | + * @param errorEvent sip错误订阅 | ||
| 274 | */ | 297 | */ |
| 275 | @Override | 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 | try { | 300 | try { |
| 278 | 301 | ||
| 279 | String ssrc = streamSession.createPlaySsrc(); | 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 | String streamMode = device.getStreamMode().toUpperCase(); | 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 | String mediaPort = null; | 315 | String mediaPort = null; |
| 283 | // 使用动态udp端口 | 316 | // 使用动态udp端口 |
| 284 | if (rtpEnable) { | 317 | if (rtpEnable) { |
| 285 | - mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | 318 | + mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + ""; |
| 286 | }else { | 319 | }else { |
| 287 | mediaPort = mediaInfo.getRtpProxyPort(); | 320 | mediaPort = mediaInfo.getRtpProxyPort(); |
| 288 | } | 321 | } |
| 289 | 322 | ||
| 290 | - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | ||
| 291 | // 添加订阅 | 323 | // 添加订阅 |
| 292 | JSONObject subscribeKey = new JSONObject(); | 324 | JSONObject subscribeKey = new JSONObject(); |
| 293 | subscribeKey.put("app", "rtp"); | 325 | subscribeKey.put("app", "rtp"); |
| @@ -297,7 +329,8 @@ public class SIPCommander implements ISIPCommander { | @@ -297,7 +329,8 @@ public class SIPCommander implements ISIPCommander { | ||
| 297 | // | 329 | // |
| 298 | StringBuffer content = new StringBuffer(200); | 330 | StringBuffer content = new StringBuffer(200); |
| 299 | content.append("v=0\r\n"); | 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 | content.append("s=Play\r\n"); | 334 | content.append("s=Play\r\n"); |
| 302 | content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); | 335 | content.append("c=IN IP4 "+mediaInfo.getWanIp()+"\r\n"); |
| 303 | content.append("t=0 0\r\n"); | 336 | content.append("t=0 0\r\n"); |
| @@ -327,17 +360,14 @@ public class SIPCommander implements ISIPCommander { | @@ -327,17 +360,14 @@ public class SIPCommander implements ISIPCommander { | ||
| 327 | } | 360 | } |
| 328 | content.append("y="+ssrc+"\r\n");//ssrc | 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 | Request request = headerProvider.createInviteRequest(device, channelId, content.toString(), null, "live", null, ssrc); | 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 | } catch ( SipException | ParseException | InvalidArgumentException e) { | 373 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| @@ -354,9 +384,10 @@ public class SIPCommander implements ISIPCommander { | @@ -354,9 +384,10 @@ public class SIPCommander implements ISIPCommander { | ||
| 354 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss | 384 | * @param endTime 结束时间,格式要求:yyyy-MM-dd HH:mm:ss |
| 355 | */ | 385 | */ |
| 356 | @Override | 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 | try { | 389 | try { |
| 359 | - MediaServerConfig mediaInfo = storager.getMediaInfo(); | 390 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| 360 | String ssrc = streamSession.createPlayBackSsrc(); | 391 | String ssrc = streamSession.createPlayBackSsrc(); |
| 361 | String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | 392 | String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); |
| 362 | // 添加订阅 | 393 | // 添加订阅 |
| @@ -378,57 +409,91 @@ public class SIPCommander implements ISIPCommander { | @@ -378,57 +409,91 @@ public class SIPCommander implements ISIPCommander { | ||
| 378 | String mediaPort = null; | 409 | String mediaPort = null; |
| 379 | // 使用动态udp端口 | 410 | // 使用动态udp端口 |
| 380 | if (rtpEnable) { | 411 | if (rtpEnable) { |
| 381 | - mediaPort = zlmUtils.getNewRTPPort(ssrc) + ""; | 412 | + mediaPort = zlmrtpServerFactory.createRTPServer(streamId) + ""; |
| 382 | }else { | 413 | }else { |
| 383 | mediaPort = mediaInfo.getRtpProxyPort(); | 414 | mediaPort = mediaInfo.getRtpProxyPort(); |
| 384 | } | 415 | } |
| 385 | String streamMode = device.getStreamMode().toUpperCase(); | 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 | content.append("y="+ssrc+"\r\n");//ssrc | 464 | content.append("y="+ssrc+"\r\n");//ssrc |
| 411 | 465 | ||
| 412 | Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "playback", null); | 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 | } catch ( SipException | ParseException | InvalidArgumentException e) { | 471 | } catch ( SipException | ParseException | InvalidArgumentException e) { |
| 418 | e.printStackTrace(); | 472 | e.printStackTrace(); |
| 419 | } | 473 | } |
| 420 | } | 474 | } |
| 421 | - | 475 | + |
| 476 | + | ||
| 477 | + | ||
| 422 | /** | 478 | /** |
| 423 | * 视频流停止 | 479 | * 视频流停止 |
| 424 | * | 480 | * |
| 425 | */ | 481 | */ |
| 426 | @Override | 482 | @Override |
| 427 | public void streamByeCmd(String ssrc) { | 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 | try { | 489 | try { |
| 430 | - ClientTransaction transaction = streamSession.get(ssrc); | 490 | + ClientTransaction transaction = streamSession.get(streamId); |
| 491 | + // 服务重启后 | ||
| 431 | if (transaction == null) { | 492 | if (transaction == null) { |
| 493 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByStreamId(streamId); | ||
| 494 | + if (streamInfo != null) { | ||
| 495 | + | ||
| 496 | + } | ||
| 432 | return; | 497 | return; |
| 433 | } | 498 | } |
| 434 | 499 | ||
| @@ -436,6 +501,9 @@ public class SIPCommander implements ISIPCommander { | @@ -436,6 +501,9 @@ public class SIPCommander implements ISIPCommander { | ||
| 436 | if (dialog == null) { | 501 | if (dialog == null) { |
| 437 | return; | 502 | return; |
| 438 | } | 503 | } |
| 504 | + | ||
| 505 | + | ||
| 506 | + | ||
| 439 | Request byeRequest = dialog.createRequest(Request.BYE); | 507 | Request byeRequest = dialog.createRequest(Request.BYE); |
| 440 | SipURI byeURI = (SipURI) byeRequest.getRequestURI(); | 508 | SipURI byeURI = (SipURI) byeRequest.getRequestURI(); |
| 441 | String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString(); | 509 | String vh = transaction.getRequest().getHeader(ViaHeader.NAME).toString(); |
| @@ -452,8 +520,16 @@ public class SIPCommander implements ISIPCommander { | @@ -452,8 +520,16 @@ public class SIPCommander implements ISIPCommander { | ||
| 452 | } else if("UDP".equals(protocol)) { | 520 | } else if("UDP".equals(protocol)) { |
| 453 | clientTransaction = udpSipProvider.getNewClientTransaction(byeRequest); | 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 | dialog.sendRequest(clientTransaction); | 529 | dialog.sendRequest(clientTransaction); |
| 456 | - streamSession.remove(ssrc); | 530 | + |
| 531 | + streamSession.remove(streamId); | ||
| 532 | + zlmrtpServerFactory.closeRTPServer(streamId); | ||
| 457 | } catch (TransactionDoesNotExistException e) { | 533 | } catch (TransactionDoesNotExistException e) { |
| 458 | e.printStackTrace(); | 534 | e.printStackTrace(); |
| 459 | } catch (SipException e) { | 535 | } catch (SipException e) { |
| @@ -571,6 +647,7 @@ public class SIPCommander implements ISIPCommander { | @@ -571,6 +647,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 571 | catalogXml.append("</Query>\r\n"); | 647 | catalogXml.append("</Query>\r\n"); |
| 572 | 648 | ||
| 573 | Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag"); | 649 | Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), "ViaDeviceInfoBranch", "FromDeviceInfoTag", "ToDeviceInfoTag"); |
| 650 | + | ||
| 574 | transmitRequest(device, request); | 651 | transmitRequest(device, request); |
| 575 | 652 | ||
| 576 | } catch (SipException | ParseException | InvalidArgumentException e) { | 653 | } catch (SipException | ParseException | InvalidArgumentException e) { |
| @@ -586,7 +663,7 @@ public class SIPCommander implements ISIPCommander { | @@ -586,7 +663,7 @@ public class SIPCommander implements ISIPCommander { | ||
| 586 | * @param device 视频设备 | 663 | * @param device 视频设备 |
| 587 | */ | 664 | */ |
| 588 | @Override | 665 | @Override |
| 589 | - public boolean catalogQuery(Device device) { | 666 | + public boolean catalogQuery(Device device, SipSubscribe.Event errorEvent) { |
| 590 | // 清空通道 | 667 | // 清空通道 |
| 591 | storager.cleanChannelsForDevice(device.getDeviceId()); | 668 | storager.cleanChannelsForDevice(device.getDeviceId()); |
| 592 | try { | 669 | try { |
| @@ -598,8 +675,9 @@ public class SIPCommander implements ISIPCommander { | @@ -598,8 +675,9 @@ public class SIPCommander implements ISIPCommander { | ||
| 598 | catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); | 675 | catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n"); |
| 599 | catalogXml.append("</Query>\r\n"); | 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 | } catch (SipException | ParseException | InvalidArgumentException e) { | 681 | } catch (SipException | ParseException | InvalidArgumentException e) { |
| 604 | e.printStackTrace(); | 682 | e.printStackTrace(); |
| 605 | return false; | 683 | return false; |
| @@ -631,7 +709,8 @@ public class SIPCommander implements ISIPCommander { | @@ -631,7 +709,8 @@ public class SIPCommander implements ISIPCommander { | ||
| 631 | recordInfoXml.append("<Type>all</Type>\r\n"); | 709 | recordInfoXml.append("<Type>all</Type>\r\n"); |
| 632 | recordInfoXml.append("</Query>\r\n"); | 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 | transmitRequest(device, request); | 714 | transmitRequest(device, request); |
| 636 | } catch (SipException | ParseException | InvalidArgumentException e) { | 715 | } catch (SipException | ParseException | InvalidArgumentException e) { |
| 637 | e.printStackTrace(); | 716 | e.printStackTrace(); |
| @@ -683,17 +762,45 @@ public class SIPCommander implements ISIPCommander { | @@ -683,17 +762,45 @@ public class SIPCommander implements ISIPCommander { | ||
| 683 | // TODO Auto-generated method stub | 762 | // TODO Auto-generated method stub |
| 684 | return false; | 763 | return false; |
| 685 | } | 764 | } |
| 686 | - | 765 | + |
| 687 | private ClientTransaction transmitRequest(Device device, Request request) throws SipException { | 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 | ClientTransaction clientTransaction = null; | 775 | ClientTransaction clientTransaction = null; |
| 689 | if("TCP".equals(device.getTransport())) { | 776 | if("TCP".equals(device.getTransport())) { |
| 690 | clientTransaction = tcpSipProvider.getNewClientTransaction(request); | 777 | clientTransaction = tcpSipProvider.getNewClientTransaction(request); |
| 691 | } else if("UDP".equals(device.getTransport())) { | 778 | } else if("UDP".equals(device.getTransport())) { |
| 692 | clientTransaction = udpSipProvider.getNewClientTransaction(request); | 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 | clientTransaction.sendRequest(); | 792 | clientTransaction.sendRequest(); |
| 695 | return clientTransaction; | 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,6 +10,7 @@ import javax.sip.SipException; | ||
| 10 | import javax.sip.message.Request; | 10 | import javax.sip.message.Request; |
| 11 | import javax.sip.message.Response; | 11 | import javax.sip.message.Response; |
| 12 | 12 | ||
| 13 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 13 | import org.dom4j.Document; | 14 | import org.dom4j.Document; |
| 14 | import org.dom4j.DocumentException; | 15 | import org.dom4j.DocumentException; |
| 15 | import org.dom4j.Element; | 16 | import org.dom4j.Element; |
| @@ -48,6 +49,8 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | @@ -48,6 +49,8 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 48 | 49 | ||
| 49 | private IVideoManagerStorager storager; | 50 | private IVideoManagerStorager storager; |
| 50 | 51 | ||
| 52 | + private IRedisCatchStorage redisCatchStorage; | ||
| 53 | + | ||
| 51 | private EventPublisher publisher; | 54 | private EventPublisher publisher; |
| 52 | 55 | ||
| 53 | private RedisUtil redis; | 56 | private RedisUtil redis; |
| @@ -294,7 +297,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | @@ -294,7 +297,7 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 294 | device.setStreamMode("UDP"); | 297 | device.setStreamMode("UDP"); |
| 295 | } | 298 | } |
| 296 | storager.updateDevice(device); | 299 | storager.updateDevice(device); |
| 297 | - cmder.catalogQuery(device); | 300 | + cmder.catalogQuery(device, null); |
| 298 | // 回复200 OK | 301 | // 回复200 OK |
| 299 | responseAck(evt); | 302 | responseAck(evt); |
| 300 | if (offLineDetector.isOnline(deviceId)) { | 303 | if (offLineDetector.isOnline(deviceId)) { |
| @@ -315,12 +318,16 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | @@ -315,12 +318,16 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 315 | try { | 318 | try { |
| 316 | Element rootElement = getRootElement(evt); | 319 | Element rootElement = getRootElement(evt); |
| 317 | String deviceId = XmlUtil.getText(rootElement, "DeviceID"); | 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 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { | 331 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { |
| 325 | e.printStackTrace(); | 332 | e.printStackTrace(); |
| 326 | } | 333 | } |
| @@ -447,10 +454,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | @@ -447,10 +454,10 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 447 | String NotifyType =XmlUtil.getText(rootElement, "NotifyType"); | 454 | String NotifyType =XmlUtil.getText(rootElement, "NotifyType"); |
| 448 | if (NotifyType.equals("121")){ | 455 | if (NotifyType.equals("121")){ |
| 449 | logger.info("媒体播放完毕,通知关流"); | 456 | logger.info("媒体播放完毕,通知关流"); |
| 450 | - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, "*"); | 457 | + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, "*"); |
| 451 | if (streamInfo != null) { | 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 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { | 463 | } catch (ParseException | SipException | InvalidArgumentException | DocumentException e) { |
| @@ -503,4 +510,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | @@ -503,4 +510,11 @@ public class MessageRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 503 | this.offLineDetector = offLineDetector; | 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,17 +107,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 107 | rPort = viaHeader.getPort(); | 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 | AddressImpl address = (AddressImpl) fromHeader.getAddress(); | 110 | AddressImpl address = (AddressImpl) fromHeader.getAddress(); |
| 115 | SipUri uri = (SipUri) address.getURI(); | 111 | SipUri uri = (SipUri) address.getURI(); |
| 116 | String deviceId = uri.getUser(); | 112 | String deviceId = uri.getUser(); |
| 117 | device = new Device(); | 113 | device = new Device(); |
| 118 | device.setStreamMode("UDP"); | 114 | device.setStreamMode("UDP"); |
| 119 | device.setDeviceId(deviceId); | 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 | if (expiresHeader != null && expiresHeader.getExpires() == 0) { | 120 | if (expiresHeader != null && expiresHeader.getExpires() == 0) { |
| 123 | registerFlag = 2; | 121 | registerFlag = 2; |
| @@ -141,9 +139,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { | @@ -141,9 +139,15 @@ public class RegisterRequestProcessor extends SIPRequestAbstractProcessor { | ||
| 141 | // 下发catelog查询目录 | 139 | // 下发catelog查询目录 |
| 142 | if (registerFlag == 1 && device != null) { | 140 | if (registerFlag == 1 && device != null) { |
| 143 | logger.info("注册成功! deviceId:" + device.getDeviceId()); | 141 | logger.info("注册成功! deviceId:" + device.getDeviceId()); |
| 142 | + boolean exists = storager.exists(device.getDeviceId()); | ||
| 143 | + device.setRegisterTimeMillis(System.currentTimeMillis()); | ||
| 144 | storager.updateDevice(device); | 144 | storager.updateDevice(device); |
| 145 | publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER); | 145 | publisher.onlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_ONLINE_REGISTER); |
| 146 | - handler.onRegister(device); | 146 | + |
| 147 | + // 只有第一次注册才更新通道 | ||
| 148 | + if (!exists) { | ||
| 149 | + handler.onRegister(device); | ||
| 150 | + } | ||
| 147 | } else if (registerFlag == 2) { | 151 | } else if (registerFlag == 2) { |
| 148 | logger.info("注销成功! deviceId:" + device.getDeviceId()); | 152 | logger.info("注销成功! deviceId:" + device.getDeviceId()); |
| 149 | publisher.outlineEventPublish(device.getDeviceId(), VideoManagerConstants.EVENT_OUTLINE_UNREGISTER); | 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,6 +12,7 @@ import javax.sip.header.ViaHeader; | ||
| 12 | import javax.sip.message.Request; | 12 | import javax.sip.message.Request; |
| 13 | import javax.sip.message.Response; | 13 | import javax.sip.message.Response; |
| 14 | 14 | ||
| 15 | +import gov.nist.javax.sip.header.CSeq; | ||
| 15 | import org.slf4j.Logger; | 16 | import org.slf4j.Logger; |
| 16 | import org.slf4j.LoggerFactory; | 17 | import org.slf4j.LoggerFactory; |
| 17 | import org.springframework.stereotype.Component; | 18 | import org.springframework.stereotype.Component; |
| @@ -23,14 +24,14 @@ import com.genersoft.iot.vmp.gb28181.transmit.response.ISIPResponseProcessor; | @@ -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 | * @author: swwheihei | 28 | * @author: swwheihei |
| 28 | - * @date: 2020年5月3日 下午4:43:52 | 29 | + * @date: 2020年5月3日 下午4:43:52 |
| 29 | */ | 30 | */ |
| 30 | @Component | 31 | @Component |
| 31 | public class InviteResponseProcessor implements ISIPResponseProcessor { | 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 | * 处理invite响应 | 37 | * 处理invite响应 |
| @@ -49,48 +50,16 @@ public class InviteResponseProcessor implements ISIPResponseProcessor { | @@ -49,48 +50,16 @@ public class InviteResponseProcessor implements ISIPResponseProcessor { | ||
| 49 | // 成功响应 | 50 | // 成功响应 |
| 50 | // 下发ack | 51 | // 下发ack |
| 51 | if (statusCode == Response.OK) { | 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 | Dialog dialog = evt.getDialog(); | 53 | Dialog dialog = evt.getDialog(); |
| 79 | CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); | 54 | CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME); |
| 80 | Request reqAck = dialog.createAck(cseq.getSeqNumber()); | 55 | Request reqAck = dialog.createAck(cseq.getSeqNumber()); |
| 81 | 56 | ||
| 82 | SipURI requestURI = (SipURI) reqAck.getRequestURI(); | 57 | SipURI requestURI = (SipURI) reqAck.getRequestURI(); |
| 83 | ViaHeader viaHeader = (ViaHeader) response.getHeader(ViaHeader.NAME); | 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 | requestURI.setHost(viaHeader.getHost()); | 59 | requestURI.setHost(viaHeader.getHost()); |
| 92 | requestURI.setPort(viaHeader.getPort()); | 60 | requestURI.setPort(viaHeader.getPort()); |
| 93 | reqAck.setRequestURI(requestURI); | 61 | reqAck.setRequestURI(requestURI); |
| 62 | + | ||
| 94 | dialog.sendAck(reqAck); | 63 | dialog.sendAck(reqAck); |
| 95 | } | 64 | } |
| 96 | } catch (InvalidArgumentException | SipException e) { | 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,6 +2,7 @@ package com.genersoft.iot.vmp.media.zlm; | ||
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson.JSONObject; | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 4 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 5 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 5 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 6 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 6 | import org.slf4j.Logger; | 7 | import org.slf4j.Logger; |
| 7 | import org.slf4j.LoggerFactory; | 8 | import org.slf4j.LoggerFactory; |
| @@ -29,6 +30,9 @@ public class ZLMHTTPProxyController { | @@ -29,6 +30,9 @@ public class ZLMHTTPProxyController { | ||
| 29 | @Autowired | 30 | @Autowired |
| 30 | private IVideoManagerStorager storager; | 31 | private IVideoManagerStorager storager; |
| 31 | 32 | ||
| 33 | + @Autowired | ||
| 34 | + private IRedisCatchStorage redisCatchStorage; | ||
| 35 | + | ||
| 32 | @Value("${media.port}") | 36 | @Value("${media.port}") |
| 33 | private int mediaHttpPort; | 37 | private int mediaHttpPort; |
| 34 | 38 | ||
| @@ -36,10 +40,10 @@ public class ZLMHTTPProxyController { | @@ -36,10 +40,10 @@ public class ZLMHTTPProxyController { | ||
| 36 | @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8") | 40 | @RequestMapping(value = "/**/**/**", produces = "application/json;charset=UTF-8") |
| 37 | public Object proxy(HttpServletRequest request, HttpServletResponse response){ | 41 | public Object proxy(HttpServletRequest request, HttpServletResponse response){ |
| 38 | 42 | ||
| 39 | - if (storager.getMediaInfo() == null) { | 43 | + if (redisCatchStorage.getMediaInfo() == null) { |
| 40 | return "未接入流媒体"; | 44 | return "未接入流媒体"; |
| 41 | } | 45 | } |
| 42 | - MediaServerConfig mediaInfo = storager.getMediaInfo(); | 46 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| 43 | String requestURI = String.format("http://%s:%s%s?%s&%s", | 47 | String requestURI = String.format("http://%s:%s%s?%s&%s", |
| 44 | mediaInfo.getLocalIP(), | 48 | mediaInfo.getLocalIP(), |
| 45 | mediaHttpPort, | 49 | mediaHttpPort, |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| @@ -4,13 +4,17 @@ import java.math.BigInteger; | @@ -4,13 +4,17 @@ import java.math.BigInteger; | ||
| 4 | import java.text.DecimalFormat; | 4 | import java.text.DecimalFormat; |
| 5 | import java.util.ArrayList; | 5 | import java.util.ArrayList; |
| 6 | import java.util.List; | 6 | import java.util.List; |
| 7 | +import java.util.UUID; | ||
| 7 | 8 | ||
| 8 | import com.alibaba.fastjson.JSON; | 9 | import com.alibaba.fastjson.JSON; |
| 9 | import com.alibaba.fastjson.JSONArray; | 10 | import com.alibaba.fastjson.JSONArray; |
| 10 | import com.genersoft.iot.vmp.common.StreamInfo; | 11 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 11 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 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 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 15 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 13 | import com.genersoft.iot.vmp.utils.IpUtil; | 16 | import com.genersoft.iot.vmp.utils.IpUtil; |
| 17 | +import com.genersoft.iot.vmp.vmanager.service.IPlayService; | ||
| 14 | import org.slf4j.Logger; | 18 | import org.slf4j.Logger; |
| 15 | import org.slf4j.LoggerFactory; | 19 | import org.slf4j.LoggerFactory; |
| 16 | import org.springframework.beans.factory.annotation.Autowired; | 20 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -44,14 +48,23 @@ public class ZLMHttpHookListener { | @@ -44,14 +48,23 @@ public class ZLMHttpHookListener { | ||
| 44 | private SIPCommander cmder; | 48 | private SIPCommander cmder; |
| 45 | 49 | ||
| 46 | @Autowired | 50 | @Autowired |
| 51 | + private IPlayService playService; | ||
| 52 | + | ||
| 53 | + @Autowired | ||
| 47 | private IVideoManagerStorager storager; | 54 | private IVideoManagerStorager storager; |
| 48 | 55 | ||
| 49 | @Autowired | 56 | @Autowired |
| 57 | + private IRedisCatchStorage redisCatchStorage; | ||
| 58 | + | ||
| 59 | + @Autowired | ||
| 50 | private ZLMRESTfulUtils zlmresTfulUtils; | 60 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 51 | 61 | ||
| 52 | @Autowired | 62 | @Autowired |
| 53 | private ZLMHttpHookSubscribe subscribe; | 63 | private ZLMHttpHookSubscribe subscribe; |
| 54 | 64 | ||
| 65 | + @Value("${media.autoApplyPlay}") | ||
| 66 | + private boolean autoApplyPlay; | ||
| 67 | + | ||
| 55 | @Value("${media.ip}") | 68 | @Value("${media.ip}") |
| 56 | private String mediaIp; | 69 | private String mediaIp; |
| 57 | 70 | ||
| @@ -135,34 +148,6 @@ public class ZLMHttpHookListener { | @@ -135,34 +148,6 @@ public class ZLMHttpHookListener { | ||
| 135 | ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); | 148 | ZLMHttpHookSubscribe.Event subscribe = this.subscribe.getSubscribe(ZLMHttpHookSubscribe.HookType.on_publish, json); |
| 136 | if (subscribe != null) subscribe.response(json); | 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 | // TODO Auto-generated method stub | 152 | // TODO Auto-generated method stub |
| 168 | 153 | ||
| @@ -268,15 +253,13 @@ public class ZLMHttpHookListener { | @@ -268,15 +253,13 @@ public class ZLMHttpHookListener { | ||
| 268 | String app = json.getString("app"); | 253 | String app = json.getString("app"); |
| 269 | String streamId = json.getString("stream"); | 254 | String streamId = json.getString("stream"); |
| 270 | boolean regist = json.getBoolean("regist"); | 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 | if ("rtp".equals(app) && !regist ) { | 257 | if ("rtp".equals(app) && !regist ) { |
| 275 | if (streamInfo!=null){ | 258 | if (streamInfo!=null){ |
| 276 | - storager.stopPlay(streamInfo); | 259 | + redisCatchStorage.stopPlay(streamInfo); |
| 277 | }else{ | 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,17 +282,15 @@ public class ZLMHttpHookListener { | ||
| 299 | logger.debug("ZLM HOOK on_stream_none_reader API调用,参数:" + json.toString()); | 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 | if (streamInfo!=null){ | 289 | if (streamInfo!=null){ |
| 309 | - storager.stopPlay(streamInfo); | 290 | + redisCatchStorage.stopPlay(streamInfo); |
| 310 | }else{ | 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 | JSONObject ret = new JSONObject(); | 296 | JSONObject ret = new JSONObject(); |
| @@ -330,7 +311,31 @@ public class ZLMHttpHookListener { | @@ -330,7 +311,31 @@ public class ZLMHttpHookListener { | ||
| 330 | logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); | 311 | logger.debug("ZLM HOOK on_stream_not_found API调用,参数:" + json.toString()); |
| 331 | } | 312 | } |
| 332 | // TODO Auto-generated method stub | 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 | JSONObject ret = new JSONObject(); | 339 | JSONObject ret = new JSONObject(); |
| 335 | ret.put("code", 0); | 340 | ret.put("code", 0); |
| 336 | ret.put("msg", "success"); | 341 | ret.put("msg", "success"); |
| @@ -354,7 +359,7 @@ public class ZLMHttpHookListener { | @@ -354,7 +359,7 @@ public class ZLMHttpHookListener { | ||
| 354 | // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0); | 359 | // MediaServerConfig mediaServerConfig = mediaServerConfigs.get(0); |
| 355 | MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); | 360 | MediaServerConfig mediaServerConfig = JSON.toJavaObject(json, MediaServerConfig.class); |
| 356 | mediaServerConfig.setLocalIP(mediaIp); | 361 | mediaServerConfig.setLocalIP(mediaIp); |
| 357 | - storager.updateMediaInfo(mediaServerConfig); | 362 | + redisCatchStorage.updateMediaInfo(mediaServerConfig); |
| 358 | // TODO Auto-generated method stub | 363 | // TODO Auto-generated method stub |
| 359 | 364 | ||
| 360 | JSONObject ret = new JSONObject(); | 365 | JSONObject ret = new JSONObject(); |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| @@ -116,4 +116,8 @@ public class ZLMRESTfulUtils { | @@ -116,4 +116,8 @@ public class ZLMRESTfulUtils { | ||
| 116 | public JSONObject openRtpServer(Map<String, Object> param){ | 116 | public JSONObject openRtpServer(Map<String, Object> param){ |
| 117 | return sendPost("openRtpServer",param); | 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 | package com.genersoft.iot.vmp.media.zlm; | 1 | package com.genersoft.iot.vmp.media.zlm; |
| 2 | 2 | ||
| 3 | import com.alibaba.fastjson.JSONObject; | 3 | import com.alibaba.fastjson.JSONObject; |
| 4 | +import org.slf4j.Logger; | ||
| 5 | +import org.slf4j.LoggerFactory; | ||
| 4 | import org.springframework.beans.factory.annotation.Autowired; | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| 5 | import org.springframework.beans.factory.annotation.Value; | 7 | import org.springframework.beans.factory.annotation.Value; |
| 6 | import org.springframework.stereotype.Component; | 8 | import org.springframework.stereotype.Component; |
| @@ -9,7 +11,9 @@ import java.util.HashMap; | @@ -9,7 +11,9 @@ import java.util.HashMap; | ||
| 9 | import java.util.Map; | 11 | import java.util.Map; |
| 10 | 12 | ||
| 11 | @Component | 13 | @Component |
| 12 | -public class ZLMUtils { | 14 | +public class ZLMRTPServerFactory { |
| 15 | + | ||
| 16 | + private Logger logger = LoggerFactory.getLogger("ZLMRTPServerFactory"); | ||
| 13 | 17 | ||
| 14 | @Value("${media.rtp.udpPortRange}") | 18 | @Value("${media.rtp.udpPortRange}") |
| 15 | private String udpPortRange; | 19 | private String udpPortRange; |
| @@ -21,19 +25,54 @@ public class ZLMUtils { | @@ -21,19 +25,54 @@ public class ZLMUtils { | ||
| 21 | 25 | ||
| 22 | private int currentPort = 0; | 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 | Map<String, Object> param = new HashMap<>(); | 29 | Map<String, Object> param = new HashMap<>(); |
| 30 | + int result = -1; | ||
| 27 | int newPort = getPortFromUdpPortRange(); | 31 | int newPort = getPortFromUdpPortRange(); |
| 28 | param.put("port", newPort); | 32 | param.put("port", newPort); |
| 29 | param.put("enable_tcp", 1); | 33 | param.put("enable_tcp", 1); |
| 30 | param.put("stream_id", streamId); | 34 | param.put("stream_id", streamId); |
| 31 | JSONObject jsonObject = zlmresTfulUtils.openRtpServer(param); | 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 | private int getPortFromUdpPortRange() { | 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,6 +4,7 @@ import com.alibaba.fastjson.JSON; | ||
| 4 | import com.alibaba.fastjson.JSONArray; | 4 | import com.alibaba.fastjson.JSONArray; |
| 5 | import com.alibaba.fastjson.JSONObject; | 5 | import com.alibaba.fastjson.JSONObject; |
| 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 7 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 7 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 8 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 8 | import okhttp3.*; | 9 | import okhttp3.*; |
| 9 | import org.slf4j.Logger; | 10 | import org.slf4j.Logger; |
| @@ -30,6 +31,9 @@ public class ZLMRunner implements CommandLineRunner { | @@ -30,6 +31,9 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 30 | @Autowired | 31 | @Autowired |
| 31 | private IVideoManagerStorager storager; | 32 | private IVideoManagerStorager storager; |
| 32 | 33 | ||
| 34 | + @Autowired | ||
| 35 | + private IRedisCatchStorage redisCatchStorage; | ||
| 36 | + | ||
| 33 | @Value("${media.ip}") | 37 | @Value("${media.ip}") |
| 34 | private String mediaIp; | 38 | private String mediaIp; |
| 35 | 39 | ||
| @@ -69,7 +73,7 @@ public class ZLMRunner implements CommandLineRunner { | @@ -69,7 +73,7 @@ public class ZLMRunner implements CommandLineRunner { | ||
| 69 | logger.info("zlm接入成功..."); | 73 | logger.info("zlm接入成功..."); |
| 70 | if (autoConfig) saveZLMConfig(); | 74 | if (autoConfig) saveZLMConfig(); |
| 71 | mediaServerConfig = getMediaServerConfig(); | 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 | package com.genersoft.iot.vmp.storager; | 1 | package com.genersoft.iot.vmp.storager; |
| 2 | 2 | ||
| 3 | import java.util.List; | 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 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 11 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 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 | * @Description:视频设备数据存储接口 | 10 | * @Description:视频设备数据存储接口 |
| @@ -18,19 +13,6 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | @@ -18,19 +13,6 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; | ||
| 18 | */ | 13 | */ |
| 19 | public interface IVideoManagerStorager { | 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 | * 根据设备ID判断设备是否存在 | 17 | * 根据设备ID判断设备是否存在 |
| 36 | * | 18 | * |
| @@ -79,7 +61,7 @@ public interface IVideoManagerStorager { | @@ -79,7 +61,7 @@ public interface IVideoManagerStorager { | ||
| 79 | * @param count 每页数量 | 61 | * @param count 每页数量 |
| 80 | * @return | 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,6 +70,7 @@ public interface IVideoManagerStorager { | ||
| 88 | * @return | 70 | * @return |
| 89 | */ | 71 | */ |
| 90 | public List<DeviceChannel> queryChannelsByDeviceId(String deviceId); | 72 | public List<DeviceChannel> queryChannelsByDeviceId(String deviceId); |
| 73 | + | ||
| 91 | /** | 74 | /** |
| 92 | * 获取某个设备的通道 | 75 | * 获取某个设备的通道 |
| 93 | * @param deviceId 设备ID | 76 | * @param deviceId 设备ID |
| @@ -95,21 +78,20 @@ public interface IVideoManagerStorager { | @@ -95,21 +78,20 @@ public interface IVideoManagerStorager { | ||
| 95 | */ | 78 | */ |
| 96 | public DeviceChannel queryChannel(String deviceId, String channelId); | 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 | * @return List<Device> 设备对象数组 | 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 | * @return List<Device> 设备对象数组 | 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,27 +117,6 @@ public interface IVideoManagerStorager { | ||
| 135 | */ | 117 | */ |
| 136 | public boolean outline(String deviceId); | 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,12 +127,8 @@ public interface IVideoManagerStorager { | ||
| 166 | * @param count | 127 | * @param count |
| 167 | * @return | 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,45 +136,4 @@ public interface IVideoManagerStorager { | ||
| 179 | */ | 136 | */ |
| 180 | void cleanChannelsForDevice(String deviceId); | 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,6 +34,7 @@ public class SpringBeanFactory implements ApplicationContextAware { | ||
| 34 | * 获取对象 这里重写了bean方法,起主要作用 | 34 | * 获取对象 这里重写了bean方法,起主要作用 |
| 35 | */ | 35 | */ |
| 36 | public static Object getBean(String beanId) throws BeansException { | 36 | public static Object getBean(String beanId) throws BeansException { |
| 37 | + if (applicationContext == null) return null; | ||
| 37 | return applicationContext.getBean(beanId); | 38 | return applicationContext.getBean(beanId); |
| 38 | } | 39 | } |
| 39 | 40 |
src/main/java/com/genersoft/iot/vmp/vmanager/device/DeviceController.java
| 1 | package com.genersoft.iot.vmp.vmanager.device; | 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 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 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 | import org.slf4j.Logger; | 6 | import org.slf4j.Logger; |
| 8 | import org.slf4j.LoggerFactory; | 7 | import org.slf4j.LoggerFactory; |
| 9 | import org.springframework.beans.factory.annotation.Autowired; | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| 10 | import org.springframework.http.HttpStatus; | 9 | import org.springframework.http.HttpStatus; |
| 11 | import org.springframework.http.ResponseEntity; | 10 | import org.springframework.http.ResponseEntity; |
| 11 | +import org.springframework.util.StringUtils; | ||
| 12 | import org.springframework.web.bind.annotation.*; | 12 | import org.springframework.web.bind.annotation.*; |
| 13 | import org.springframework.web.context.request.async.DeferredResult; | 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,6 +19,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | ||
| 19 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 19 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 20 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 20 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 21 | 21 | ||
| 22 | +import javax.sip.message.Response; | ||
| 23 | + | ||
| 22 | @CrossOrigin | 24 | @CrossOrigin |
| 23 | @RestController | 25 | @RestController |
| 24 | @RequestMapping("/api") | 26 | @RequestMapping("/api") |
| @@ -50,13 +52,13 @@ public class DeviceController { | @@ -50,13 +52,13 @@ public class DeviceController { | ||
| 50 | } | 52 | } |
| 51 | 53 | ||
| 52 | @GetMapping("/devices") | 54 | @GetMapping("/devices") |
| 53 | - public PageResult<Device> devices(int page, int count){ | 55 | + public PageInfo<Device> devices(int page, int count){ |
| 54 | 56 | ||
| 55 | if (logger.isDebugEnabled()) { | 57 | if (logger.isDebugEnabled()) { |
| 56 | logger.debug("查询所有视频设备API调用"); | 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,18 +68,33 @@ public class DeviceController { | ||
| 66 | * @param count 每页条数 | 68 | * @param count 每页条数 |
| 67 | * @return 通道列表 | 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 | @GetMapping("/devices/{deviceId}/channels") | 82 | @GetMapping("/devices/{deviceId}/channels") |
| 70 | - public ResponseEntity<PageResult> channels(@PathVariable String deviceId, | 83 | + public ResponseEntity<PageInfo> channels(@PathVariable String deviceId, |
| 71 | int page, int count, | 84 | int page, int count, |
| 72 | @RequestParam(required = false) String query, | 85 | @RequestParam(required = false) String query, |
| 73 | - @RequestParam(required = false) String online, | 86 | + @RequestParam(required = false) Boolean online, |
| 74 | @RequestParam(required = false) Boolean channelType | 87 | @RequestParam(required = false) Boolean channelType |
| 75 | ){ | 88 | ){ |
| 76 | 89 | ||
| 77 | if (logger.isDebugEnabled()) { | 90 | if (logger.isDebugEnabled()) { |
| 78 | logger.debug("查询所有视频设备API调用"); | 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 | return new ResponseEntity<>(pageResult,HttpStatus.OK); | 98 | return new ResponseEntity<>(pageResult,HttpStatus.OK); |
| 82 | } | 99 | } |
| 83 | 100 | ||
| @@ -86,11 +103,25 @@ public class DeviceController { | @@ -86,11 +103,25 @@ public class DeviceController { | ||
| 86 | 103 | ||
| 87 | if (logger.isDebugEnabled()) { | 104 | if (logger.isDebugEnabled()) { |
| 88 | } | 105 | } |
| 89 | - logger.debug("设备信息同步API调用,deviceId:" + deviceId); | 106 | + logger.debug("设备通道信息同步API调用,deviceId:" + deviceId); |
| 90 | 107 | ||
| 91 | Device device = storager.queryVideoDevice(deviceId); | 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 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); | 125 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_CATALOG+deviceId, result); |
| 95 | return result; | 126 | return result; |
| 96 | } | 127 | } |
| @@ -124,7 +155,7 @@ public class DeviceController { | @@ -124,7 +155,7 @@ public class DeviceController { | ||
| 124 | * @return 子通道列表 | 155 | * @return 子通道列表 |
| 125 | */ | 156 | */ |
| 126 | @GetMapping("/subChannels/{deviceId}/{channelId}/channels") | 157 | @GetMapping("/subChannels/{deviceId}/{channelId}/channels") |
| 127 | - public ResponseEntity<PageResult> subChannels(@PathVariable String deviceId, | 158 | + public ResponseEntity<PageInfo> subChannels(@PathVariable String deviceId, |
| 128 | @PathVariable String channelId, | 159 | @PathVariable String channelId, |
| 129 | int page, | 160 | int page, |
| 130 | int count, | 161 | int count, |
| @@ -137,23 +168,23 @@ public class DeviceController { | @@ -137,23 +168,23 @@ public class DeviceController { | ||
| 137 | } | 168 | } |
| 138 | DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); | 169 | DeviceChannel deviceChannel = storager.queryChannel(deviceId,channelId); |
| 139 | if (deviceChannel == null) { | 170 | if (deviceChannel == null) { |
| 140 | - PageResult<DeviceChannel> deviceChannelPageResult = new PageResult<>(); | 171 | + PageInfo<DeviceChannel> deviceChannelPageResult = new PageInfo<>(); |
| 141 | return new ResponseEntity<>(deviceChannelPageResult,HttpStatus.OK); | 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 | return new ResponseEntity<>(pageResult,HttpStatus.OK); | 176 | return new ResponseEntity<>(pageResult,HttpStatus.OK); |
| 146 | } | 177 | } |
| 147 | 178 | ||
| 148 | @PostMapping("/channel/update/{deviceId}") | 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 | storager.updateChannel(deviceId, channel); | 181 | storager.updateChannel(deviceId, channel); |
| 151 | return new ResponseEntity<>(null,HttpStatus.OK); | 182 | return new ResponseEntity<>(null,HttpStatus.OK); |
| 152 | } | 183 | } |
| 153 | 184 | ||
| 154 | @GetMapping("/devices/{deviceId}/transport/{streamMode}") | 185 | @GetMapping("/devices/{deviceId}/transport/{streamMode}") |
| 155 | @PostMapping("/devices/{deviceId}/transport/{streamMode}") | 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 | Device device = storager.queryVideoDevice(deviceId); | 188 | Device device = storager.queryVideoDevice(deviceId); |
| 158 | device.setStreamMode(streamMode); | 189 | device.setStreamMode(streamMode); |
| 159 | storager.updateDevice(device); | 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,6 +7,8 @@ import com.genersoft.iot.vmp.conf.MediaServerConfig; | ||
| 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 9 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 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 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; | 12 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| 11 | import org.slf4j.Logger; | 13 | import org.slf4j.Logger; |
| 12 | import org.slf4j.LoggerFactory; | 14 | import org.slf4j.LoggerFactory; |
| @@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | @@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | ||
| 27 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 29 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 28 | import org.springframework.web.context.request.async.DeferredResult; | 30 | import org.springframework.web.context.request.async.DeferredResult; |
| 29 | 31 | ||
| 32 | +import javax.sip.message.Response; | ||
| 30 | import java.text.DecimalFormat; | 33 | import java.text.DecimalFormat; |
| 31 | import java.util.UUID; | 34 | import java.util.UUID; |
| 32 | 35 | ||
| @@ -44,6 +47,9 @@ public class PlayController { | @@ -44,6 +47,9 @@ public class PlayController { | ||
| 44 | private IVideoManagerStorager storager; | 47 | private IVideoManagerStorager storager; |
| 45 | 48 | ||
| 46 | @Autowired | 49 | @Autowired |
| 50 | + private IRedisCatchStorage redisCatchStorage; | ||
| 51 | + | ||
| 52 | + @Autowired | ||
| 47 | private ZLMRESTfulUtils zlmresTfulUtils; | 53 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 48 | 54 | ||
| 49 | @Autowired | 55 | @Autowired |
| @@ -58,18 +64,11 @@ public class PlayController { | @@ -58,18 +64,11 @@ public class PlayController { | ||
| 58 | 64 | ||
| 59 | 65 | ||
| 60 | Device device = storager.queryVideoDevice(deviceId); | 66 | Device device = storager.queryVideoDevice(deviceId); |
| 61 | - StreamInfo streamInfo = storager.queryPlayByDevice(deviceId, channelId); | 67 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(deviceId, channelId); |
| 62 | 68 | ||
| 63 | UUID uuid = UUID.randomUUID(); | 69 | UUID uuid = UUID.randomUUID(); |
| 64 | DeferredResult<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(); | 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 | // 录像查询以channelId作为deviceId查询 | 72 | // 录像查询以channelId作为deviceId查询 |
| 74 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); | 73 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); |
| 75 | 74 | ||
| @@ -78,9 +77,15 @@ public class PlayController { | @@ -78,9 +77,15 @@ public class PlayController { | ||
| 78 | cmder.playStreamCmd(device, channelId, (JSONObject response) -> { | 77 | cmder.playStreamCmd(device, channelId, (JSONObject response) -> { |
| 79 | logger.info("收到订阅消息: " + response.toJSONString()); | 78 | logger.info("收到订阅消息: " + response.toJSONString()); |
| 80 | playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); | 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 | } else { | 87 | } else { |
| 83 | - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); | 88 | + String streamId = streamInfo.getStreamId(); |
| 84 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); | 89 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); |
| 85 | if (rtpInfo.getBoolean("exist")) { | 90 | if (rtpInfo.getBoolean("exist")) { |
| 86 | RequestMessage msg = new RequestMessage(); | 91 | RequestMessage msg = new RequestMessage(); |
| @@ -88,58 +93,107 @@ public class PlayController { | @@ -88,58 +93,107 @@ public class PlayController { | ||
| 88 | msg.setData(JSON.toJSONString(streamInfo)); | 93 | msg.setData(JSON.toJSONString(streamInfo)); |
| 89 | resultHolder.invokeResult(msg); | 94 | resultHolder.invokeResult(msg); |
| 90 | } else { | 95 | } else { |
| 91 | - storager.stopPlay(streamInfo); | ||
| 92 | - // TODO playStreamCmd 超时处理 | 96 | + redisCatchStorage.stopPlay(streamInfo); |
| 93 | cmder.playStreamCmd(device, channelId, (JSONObject response) -> { | 97 | cmder.playStreamCmd(device, channelId, (JSONObject response) -> { |
| 94 | logger.info("收到订阅消息: " + response.toJSONString()); | 98 | logger.info("收到订阅消息: " + response.toJSONString()); |
| 95 | playService.onPublishHandlerForPlay(response, deviceId, channelId, uuid.toString()); | 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 | return result; | 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 | JSONObject json = new JSONObject(); | 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 | } else { | 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 | * 将不是h264的视频通过ffmpeg 转码为h264 + aac | 180 | * 将不是h264的视频通过ffmpeg 转码为h264 + aac |
| 126 | - * @param ssrc | 181 | + * @param streamId 流ID |
| 127 | * @return | 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 | if (streamInfo == null) { | 187 | if (streamInfo == null) { |
| 133 | logger.warn("视频转码API调用失败!, 视频流已经停止!"); | 188 | logger.warn("视频转码API调用失败!, 视频流已经停止!"); |
| 134 | return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK); | 189 | return new ResponseEntity<String>("未找到视频流信息, 视频流可能已经停止", HttpStatus.OK); |
| 135 | } | 190 | } |
| 136 | - String streamId = String.format("%08x", Integer.parseInt(ssrc)).toUpperCase(); | ||
| 137 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); | 191 | JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); |
| 138 | if (!rtpInfo.getBoolean("exist")) { | 192 | if (!rtpInfo.getBoolean("exist")) { |
| 139 | logger.warn("视频转码API调用失败!, 视频流已停止推流!"); | 193 | logger.warn("视频转码API调用失败!, 视频流已停止推流!"); |
| 140 | return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK); | 194 | return new ResponseEntity<String>("推流信息在流媒体中不存在, 视频流可能已停止推流", HttpStatus.OK); |
| 141 | } else { | 195 | } else { |
| 142 | - MediaServerConfig mediaInfo = storager.getMediaInfo(); | 196 | + MediaServerConfig mediaInfo = redisCatchStorage.getMediaInfo(); |
| 143 | String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(), | 197 | String dstUrl = String.format("rtmp://%s:%s/convert/%s", "127.0.0.1", mediaInfo.getRtmpPort(), |
| 144 | streamId ); | 198 | streamId ); |
| 145 | String srcUrl = String.format("rtsp://%s:%s/rtp/%s", "127.0.0.1", mediaInfo.getRtspPort(), streamId); | 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 +6,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; | ||
| 6 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | 6 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 8 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 8 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 9 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 9 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; | 10 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| 10 | import org.slf4j.Logger; | 11 | import org.slf4j.Logger; |
| 11 | import org.slf4j.LoggerFactory; | 12 | import org.slf4j.LoggerFactory; |
| @@ -27,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | @@ -27,6 +28,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | ||
| 27 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 28 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 28 | import org.springframework.web.context.request.async.DeferredResult; | 29 | import org.springframework.web.context.request.async.DeferredResult; |
| 29 | 30 | ||
| 31 | +import javax.sip.message.Response; | ||
| 30 | import java.util.UUID; | 32 | import java.util.UUID; |
| 31 | 33 | ||
| 32 | @CrossOrigin | 34 | @CrossOrigin |
| @@ -43,6 +45,9 @@ public class PlaybackController { | @@ -43,6 +45,9 @@ public class PlaybackController { | ||
| 43 | private IVideoManagerStorager storager; | 45 | private IVideoManagerStorager storager; |
| 44 | 46 | ||
| 45 | @Autowired | 47 | @Autowired |
| 48 | + private IRedisCatchStorage redisCatchStorage; | ||
| 49 | + | ||
| 50 | + @Autowired | ||
| 46 | private ZLMRESTfulUtils zlmresTfulUtils; | 51 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 47 | 52 | ||
| 48 | @Autowired | 53 | @Autowired |
| @@ -69,15 +74,21 @@ public class PlaybackController { | @@ -69,15 +74,21 @@ public class PlaybackController { | ||
| 69 | resultHolder.invokeResult(msg); | 74 | resultHolder.invokeResult(msg); |
| 70 | }); | 75 | }); |
| 71 | Device device = storager.queryVideoDevice(deviceId); | 76 | Device device = storager.queryVideoDevice(deviceId); |
| 72 | - StreamInfo streamInfo = storager.queryPlaybackByDevice(deviceId, channelId); | 77 | + StreamInfo streamInfo = redisCatchStorage.queryPlaybackByDevice(deviceId, channelId); |
| 73 | if (streamInfo != null) { | 78 | if (streamInfo != null) { |
| 74 | // 停止之前的回放 | 79 | // 停止之前的回放 |
| 75 | - cmder.streamByeCmd(streamInfo.getSsrc()); | 80 | + cmder.streamByeCmd(streamInfo.getStreamId()); |
| 76 | } | 81 | } |
| 77 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); | 82 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid, result); |
| 78 | cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { | 83 | cmder.playbackStreamCmd(device, channelId, startTime, endTime, (JSONObject response) -> { |
| 79 | logger.info("收到订阅消息: " + response.toJSONString()); | 84 | logger.info("收到订阅消息: " + response.toJSONString()); |
| 80 | playService.onPublishHandlerForPlayBack(response, deviceId, channelId, uuid.toString()); | 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 | return result; | 94 | return result; |
src/main/java/com/genersoft/iot/vmp/vmanager/ptz/PtzController.java
| @@ -29,15 +29,14 @@ public class PtzController { | @@ -29,15 +29,14 @@ public class PtzController { | ||
| 29 | private IVideoManagerStorager storager; | 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 | @PostMapping("/ptz/{deviceId}/{channelId}") | 41 | @PostMapping("/ptz/{deviceId}/{channelId}") |
| 43 | public ResponseEntity<String> ptz(@PathVariable String deviceId,@PathVariable String channelId,int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed){ | 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 | package com.genersoft.iot.vmp.vmanager.record; | 1 | package com.genersoft.iot.vmp.vmanager.record; |
| 2 | 2 | ||
| 3 | +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | ||
| 3 | import org.slf4j.Logger; | 4 | import org.slf4j.Logger; |
| 4 | import org.slf4j.LoggerFactory; | 5 | import org.slf4j.LoggerFactory; |
| 5 | import org.springframework.beans.factory.annotation.Autowired; | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| @@ -32,7 +33,7 @@ public class RecordController { | @@ -32,7 +33,7 @@ public class RecordController { | ||
| 32 | 33 | ||
| 33 | @Autowired | 34 | @Autowired |
| 34 | private DeferredResultHolder resultHolder; | 35 | private DeferredResultHolder resultHolder; |
| 35 | - | 36 | + |
| 36 | @GetMapping("/record/{deviceId}/{channelId}") | 37 | @GetMapping("/record/{deviceId}/{channelId}") |
| 37 | public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){ | 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,9 +43,17 @@ public class RecordController { | ||
| 42 | 43 | ||
| 43 | Device device = storager.queryVideoDevice(deviceId); | 44 | Device device = storager.queryVideoDevice(deviceId); |
| 44 | cmder.recordInfoQuery(device, channelId, startTime, endTime); | 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 | // 录像查询以channelId作为deviceId查询 | 48 | // 录像查询以channelId作为deviceId查询 |
| 47 | resultHolder.put(DeferredResultHolder.CALLBACK_CMD_RECORDINFO+channelId, result); | 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 | return result; | 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,8 +4,10 @@ import com.alibaba.fastjson.JSON; | ||
| 4 | import com.alibaba.fastjson.JSONObject; | 4 | import com.alibaba.fastjson.JSONObject; |
| 5 | import com.genersoft.iot.vmp.common.StreamInfo; | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; | 6 | import com.genersoft.iot.vmp.conf.MediaServerConfig; |
| 7 | +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | ||
| 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; | 9 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 10 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 9 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 11 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 10 | import com.genersoft.iot.vmp.vmanager.play.PlayController; | 12 | import com.genersoft.iot.vmp.vmanager.play.PlayController; |
| 11 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; | 13 | import com.genersoft.iot.vmp.vmanager.service.IPlayService; |
| @@ -25,6 +27,9 @@ public class PlayServiceImpl implements IPlayService { | @@ -25,6 +27,9 @@ public class PlayServiceImpl implements IPlayService { | ||
| 25 | private IVideoManagerStorager storager; | 27 | private IVideoManagerStorager storager; |
| 26 | 28 | ||
| 27 | @Autowired | 29 | @Autowired |
| 30 | + private IRedisCatchStorage redisCatchStorage; | ||
| 31 | + | ||
| 32 | + @Autowired | ||
| 28 | private DeferredResultHolder resultHolder; | 33 | private DeferredResultHolder resultHolder; |
| 29 | 34 | ||
| 30 | @Override | 35 | @Override |
| @@ -33,7 +38,13 @@ public class PlayServiceImpl implements IPlayService { | @@ -33,7 +38,13 @@ public class PlayServiceImpl implements IPlayService { | ||
| 33 | msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); | 38 | msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); |
| 34 | StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); | 39 | StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); |
| 35 | if (streamInfo != null) { | 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 | msg.setData(JSON.toJSONString(streamInfo)); | 48 | msg.setData(JSON.toJSONString(streamInfo)); |
| 38 | resultHolder.invokeResult(msg); | 49 | resultHolder.invokeResult(msg); |
| 39 | } else { | 50 | } else { |
| @@ -49,7 +60,7 @@ public class PlayServiceImpl implements IPlayService { | @@ -49,7 +60,7 @@ public class PlayServiceImpl implements IPlayService { | ||
| 49 | msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); | 60 | msg.setId(DeferredResultHolder.CALLBACK_CMD_PlAY + uuid); |
| 50 | StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); | 61 | StreamInfo streamInfo = onPublishHandler(resonse, deviceId, channelId, uuid); |
| 51 | if (streamInfo != null) { | 62 | if (streamInfo != null) { |
| 52 | - storager.startPlayback(streamInfo); | 63 | + redisCatchStorage.startPlayback(streamInfo); |
| 53 | msg.setData(JSON.toJSONString(streamInfo)); | 64 | msg.setData(JSON.toJSONString(streamInfo)); |
| 54 | resultHolder.invokeResult(msg); | 65 | resultHolder.invokeResult(msg); |
| 55 | } else { | 66 | } else { |
| @@ -61,13 +72,11 @@ public class PlayServiceImpl implements IPlayService { | @@ -61,13 +72,11 @@ public class PlayServiceImpl implements IPlayService { | ||
| 61 | 72 | ||
| 62 | public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { | 73 | public StreamInfo onPublishHandler(JSONObject resonse, String deviceId, String channelId, String uuid) { |
| 63 | String streamId = resonse.getString("id"); | 74 | String streamId = resonse.getString("id"); |
| 64 | - String ssrc = new DecimalFormat("0000000000").format(Integer.parseInt(streamId, 16)); | ||
| 65 | StreamInfo streamInfo = new StreamInfo(); | 75 | StreamInfo streamInfo = new StreamInfo(); |
| 66 | - streamInfo.setSsrc(ssrc); | ||
| 67 | streamInfo.setStreamId(streamId); | 76 | streamInfo.setStreamId(streamId); |
| 68 | streamInfo.setDeviceID(deviceId); | 77 | streamInfo.setDeviceID(deviceId); |
| 69 | streamInfo.setCahnnelId(channelId); | 78 | streamInfo.setCahnnelId(channelId); |
| 70 | - MediaServerConfig mediaServerConfig = storager.getMediaInfo(); | 79 | + MediaServerConfig mediaServerConfig = redisCatchStorage.getMediaInfo(); |
| 71 | 80 | ||
| 72 | streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | 81 | streamInfo.setFlv(String.format("http://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); |
| 73 | streamInfo.setWs_flv(String.format("ws://%s:%s/rtp/%s.flv", mediaServerConfig.getWanIp(), mediaServerConfig.getHttpPort(), streamId)); | 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 | package com.genersoft.iot.vmp.web; | 1 | package com.genersoft.iot.vmp.web; |
| 2 | 2 | ||
| 3 | -import com.alibaba.fastjson.JSON; | ||
| 4 | import com.alibaba.fastjson.JSONArray; | 3 | import com.alibaba.fastjson.JSONArray; |
| 5 | import com.alibaba.fastjson.JSONObject; | 4 | import com.alibaba.fastjson.JSONObject; |
| 6 | -import com.genersoft.iot.vmp.common.PageResult; | ||
| 7 | import com.genersoft.iot.vmp.gb28181.bean.Device; | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 6 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 9 | import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; | 7 | import com.genersoft.iot.vmp.gb28181.event.DeviceOffLineDetector; |
| 10 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 11 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 9 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 12 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 10 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 13 | -import com.genersoft.iot.vmp.vmanager.device.DeviceController; | 11 | +import com.github.pagehelper.PageInfo; |
| 14 | import org.slf4j.Logger; | 12 | import org.slf4j.Logger; |
| 15 | import org.slf4j.LoggerFactory; | 13 | import org.slf4j.LoggerFactory; |
| 16 | import org.springframework.beans.factory.annotation.Autowired; | 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 | import org.springframework.web.bind.annotation.*; | 15 | import org.springframework.web.bind.annotation.*; |
| 21 | 16 | ||
| 22 | import java.util.List; | 17 | import java.util.List; |
| @@ -65,12 +60,12 @@ public class ApiDeviceController { | @@ -65,12 +60,12 @@ public class ApiDeviceController { | ||
| 65 | JSONObject result = new JSONObject(); | 60 | JSONObject result = new JSONObject(); |
| 66 | List<Device> devices; | 61 | List<Device> devices; |
| 67 | if (start == null || limit ==null) { | 62 | if (start == null || limit ==null) { |
| 68 | - devices = storager.queryVideoDeviceList(null); | 63 | + devices = storager.queryVideoDeviceList(); |
| 69 | result.put("DeviceCount", devices.size()); | 64 | result.put("DeviceCount", devices.size()); |
| 70 | }else { | 65 | }else { |
| 71 | - PageResult<Device> deviceList = storager.queryVideoDeviceList(null, start/limit, limit); | 66 | + PageInfo<Device> deviceList = storager.queryVideoDeviceList(start/limit, limit); |
| 72 | result.put("DeviceCount", deviceList.getTotal()); | 67 | result.put("DeviceCount", deviceList.getTotal()); |
| 73 | - devices = deviceList.getData(); | 68 | + devices = deviceList.getList(); |
| 74 | } | 69 | } |
| 75 | 70 | ||
| 76 | JSONArray deviceJSONList = new JSONArray(); | 71 | JSONArray deviceJSONList = new JSONArray(); |
| @@ -86,8 +81,8 @@ public class ApiDeviceController { | @@ -86,8 +81,8 @@ public class ApiDeviceController { | ||
| 86 | deviceJsonObject.put("Online", device.getOnline() == 1); | 81 | deviceJsonObject.put("Online", device.getOnline() == 1); |
| 87 | deviceJsonObject.put("Password", ""); | 82 | deviceJsonObject.put("Password", ""); |
| 88 | deviceJsonObject.put("MediaTransport", device.getTransport()); | 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 | deviceJsonObject.put("LastRegisterAt", ""); | 86 | deviceJsonObject.put("LastRegisterAt", ""); |
| 92 | deviceJsonObject.put("LastKeepaliveAt", ""); | 87 | deviceJsonObject.put("LastKeepaliveAt", ""); |
| 93 | deviceJsonObject.put("UpdatedAt", ""); | 88 | deviceJsonObject.put("UpdatedAt", ""); |
| @@ -123,9 +118,9 @@ public class ApiDeviceController { | @@ -123,9 +118,9 @@ public class ApiDeviceController { | ||
| 123 | deviceChannels = storager.queryChannelsByDeviceId(serial); | 118 | deviceChannels = storager.queryChannelsByDeviceId(serial); |
| 124 | result.put("ChannelCount", deviceChannels.size()); | 119 | result.put("ChannelCount", deviceChannels.size()); |
| 125 | }else { | 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 | result.put("ChannelCount", pageResult.getTotal()); | 122 | result.put("ChannelCount", pageResult.getTotal()); |
| 128 | - deviceChannels = pageResult.getData(); | 123 | + deviceChannels = pageResult.getList(); |
| 129 | } | 124 | } |
| 130 | 125 | ||
| 131 | JSONArray channleJSONList = new JSONArray(); | 126 | JSONArray channleJSONList = new JSONArray(); |
| @@ -159,7 +154,7 @@ public class ApiDeviceController { | @@ -159,7 +154,7 @@ public class ApiDeviceController { | ||
| 159 | deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球, | 154 | deviceJOSNChannel.put("PTZType ", deviceChannel.getPTZType()); // 云台类型, 0 - 未知, 1 - 球机, 2 - 半球, |
| 160 | // 3 - 固定枪机, 4 - 遥控枪机 | 155 | // 3 - 固定枪机, 4 - 遥控枪机 |
| 161 | deviceJOSNChannel.put("CustomPTZType", ""); | 156 | deviceJOSNChannel.put("CustomPTZType", ""); |
| 162 | - deviceJOSNChannel.put("StreamID", deviceChannel.getSsrc()); // StreamID 直播流ID, 有值表示正在直播 | 157 | + deviceJOSNChannel.put("StreamID", deviceChannel.getStreamId()); // StreamID 直播流ID, 有值表示正在直播 |
| 163 | deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数 | 158 | deviceJOSNChannel.put("NumOutputs ", -1); // 直播在线人数 |
| 164 | channleJSONList.add(deviceJOSNChannel); | 159 | channleJSONList.add(deviceJOSNChannel); |
| 165 | } | 160 | } |
src/main/java/com/genersoft/iot/vmp/web/ApiStreamController.java
| @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; | ||
| 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; | 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 9 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; | 9 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 10 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | 10 | import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; |
| 11 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | ||
| 11 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; | 12 | import com.genersoft.iot.vmp.storager.IVideoManagerStorager; |
| 12 | import com.genersoft.iot.vmp.vmanager.play.PlayController; | 13 | import com.genersoft.iot.vmp.vmanager.play.PlayController; |
| 13 | import org.slf4j.Logger; | 14 | import org.slf4j.Logger; |
| @@ -17,6 +18,7 @@ import org.springframework.beans.factory.annotation.Value; | @@ -17,6 +18,7 @@ import org.springframework.beans.factory.annotation.Value; | ||
| 17 | import org.springframework.http.HttpStatus; | 18 | import org.springframework.http.HttpStatus; |
| 18 | import org.springframework.http.ResponseEntity; | 19 | import org.springframework.http.ResponseEntity; |
| 19 | import org.springframework.web.bind.annotation.*; | 20 | import org.springframework.web.bind.annotation.*; |
| 21 | +import org.springframework.web.context.request.async.DeferredResult; | ||
| 20 | 22 | ||
| 21 | /** | 23 | /** |
| 22 | * 兼容LiveGBS的API:实时直播 | 24 | * 兼容LiveGBS的API:实时直播 |
| @@ -34,12 +36,17 @@ public class ApiStreamController { | @@ -34,12 +36,17 @@ public class ApiStreamController { | ||
| 34 | @Autowired | 36 | @Autowired |
| 35 | private IVideoManagerStorager storager; | 37 | private IVideoManagerStorager storager; |
| 36 | 38 | ||
| 37 | - private boolean closeWaitRTPInfo = false; | 39 | + @Autowired |
| 40 | + private IRedisCatchStorage redisCatchStorage; | ||
| 38 | 41 | ||
| 39 | 42 | ||
| 40 | @Autowired | 43 | @Autowired |
| 41 | private ZLMRESTfulUtils zlmresTfulUtils; | 44 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 42 | 45 | ||
| 46 | + | ||
| 47 | + @Autowired | ||
| 48 | + private PlayController playController; | ||
| 49 | + | ||
| 43 | /** | 50 | /** |
| 44 | * 实时直播 - 开始直播 | 51 | * 实时直播 - 开始直播 |
| 45 | * @param serial 设备编号 | 52 | * @param serial 设备编号 |
| @@ -54,126 +61,54 @@ public class ApiStreamController { | @@ -54,126 +61,54 @@ public class ApiStreamController { | ||
| 54 | * @return | 61 | * @return |
| 55 | */ | 62 | */ |
| 56 | @RequestMapping(value = "/start") | 63 | @RequestMapping(value = "/start") |
| 57 | - private JSONObject start(String serial , | ||
| 58 | - @RequestParam(required = false)Integer channel , | ||
| 59 | - @RequestParam(required = false)String code, | ||
| 60 | - @RequestParam(required = false)String cdn, | ||
| 61 | - @RequestParam(required = false)String audio, | ||
| 62 | - @RequestParam(required = false)String transport, | ||
| 63 | - @RequestParam(required = false)String checkchannelstatus , | ||
| 64 | - @RequestParam(required = false)String transportmode, | ||
| 65 | - @RequestParam(required = false)String timeout | 64 | + private DeferredResult<JSONObject> start(String serial , |
| 65 | + @RequestParam(required = false)Integer channel , | ||
| 66 | + @RequestParam(required = false)String code, | ||
| 67 | + @RequestParam(required = false)String cdn, | ||
| 68 | + @RequestParam(required = false)String audio, | ||
| 69 | + @RequestParam(required = false)String transport, | ||
| 70 | + @RequestParam(required = false)String checkchannelstatus , | ||
| 71 | + @RequestParam(required = false)String transportmode, | ||
| 72 | + @RequestParam(required = false)String timeout | ||
| 66 | 73 | ||
| 67 | ){ | 74 | ){ |
| 68 | - int getEncoding = closeWaitRTPInfo? 1: 0; | 75 | + DeferredResult<JSONObject> resultDeferredResult = new DeferredResult<JSONObject>(); |
| 69 | Device device = storager.queryVideoDevice(serial); | 76 | Device device = storager.queryVideoDevice(serial); |
| 70 | - | ||
| 71 | if (device == null ) { | 77 | if (device == null ) { |
| 72 | JSONObject result = new JSONObject(); | 78 | JSONObject result = new JSONObject(); |
| 73 | result.put("error","device[ " + serial + " ]未找到"); | 79 | result.put("error","device[ " + serial + " ]未找到"); |
| 74 | - return result; | 80 | + resultDeferredResult.setResult(result); |
| 75 | }else if (device.getOnline() == 0) { | 81 | }else if (device.getOnline() == 0) { |
| 76 | JSONObject result = new JSONObject(); | 82 | JSONObject result = new JSONObject(); |
| 77 | result.put("error","device[ " + code + " ]offline"); | 83 | result.put("error","device[ " + code + " ]offline"); |
| 78 | - return result; | 84 | + resultDeferredResult.setResult(result); |
| 79 | } | 85 | } |
| 86 | + resultDeferredResult.onTimeout(()->{ | ||
| 87 | + logger.info("播放等待超时"); | ||
| 88 | + JSONObject result = new JSONObject(); | ||
| 89 | + result.put("error","timeout"); | ||
| 90 | + resultDeferredResult.setResult(result); | ||
| 91 | + | ||
| 92 | + // 清理RTP server | ||
| 93 | + }); | ||
| 80 | 94 | ||
| 81 | DeviceChannel deviceChannel = storager.queryChannel(serial, code); | 95 | DeviceChannel deviceChannel = storager.queryChannel(serial, code); |
| 82 | if (deviceChannel == null) { | 96 | if (deviceChannel == null) { |
| 83 | JSONObject result = new JSONObject(); | 97 | JSONObject result = new JSONObject(); |
| 84 | result.put("error","channel[ " + code + " ]未找到"); | 98 | result.put("error","channel[ " + code + " ]未找到"); |
| 85 | - return result; | 99 | + resultDeferredResult.setResult(result); |
| 86 | }else if (deviceChannel.getStatus() == 0) { | 100 | }else if (deviceChannel.getStatus() == 0) { |
| 87 | JSONObject result = new JSONObject(); | 101 | JSONObject result = new JSONObject(); |
| 88 | result.put("error","channel[ " + code + " ]offline"); | 102 | result.put("error","channel[ " + code + " ]offline"); |
| 89 | - return result; | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - // 查询是否已经在播放 | ||
| 93 | - StreamInfo streamInfo = storager.queryPlayByDevice(device.getDeviceId(), code); | ||
| 94 | - if (streamInfo == null) { | ||
| 95 | - logger.debug("streamInfo 等于null, 重新点播"); | ||
| 96 | -// streamInfo = cmder.playStreamCmd(device, code); | ||
| 97 | - }else { | ||
| 98 | - logger.debug("streamInfo 不等于null, 向流媒体查询是否正在推流"); | ||
| 99 | - String streamId = String.format("%08x", Integer.parseInt(streamInfo.getSsrc())).toUpperCase(); | ||
| 100 | - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(streamId); | ||
| 101 | - if (rtpInfo.getBoolean("exist")) { | ||
| 102 | - logger.debug("向流媒体查询正在推流, 直接返回: " + streamInfo.getRtsp()); | ||
| 103 | - JSONObject result = new JSONObject(); | ||
| 104 | - result.put("StreamID", streamInfo.getSsrc()); | ||
| 105 | - result.put("DeviceID", device.getDeviceId()); | ||
| 106 | - result.put("ChannelID", code); | ||
| 107 | - result.put("ChannelName", deviceChannel.getName()); | ||
| 108 | - result.put("ChannelCustomName", ""); | ||
| 109 | - result.put("FLV", streamInfo.getFlv()); | ||
| 110 | - result.put("WS_FLV", streamInfo.getWs_flv()); | ||
| 111 | - result.put("RTMP", streamInfo.getRtmp()); | ||
| 112 | - result.put("HLS", streamInfo.getHls()); | ||
| 113 | - result.put("RTSP", streamInfo.getRtsp()); | ||
| 114 | - result.put("CDN", ""); | ||
| 115 | - result.put("SnapURL", ""); | ||
| 116 | - result.put("Transport", device.getTransport()); | ||
| 117 | - result.put("StartAt", ""); | ||
| 118 | - result.put("Duration", ""); | ||
| 119 | - result.put("SourceVideoCodecName", ""); | ||
| 120 | - result.put("SourceVideoWidth", ""); | ||
| 121 | - result.put("SourceVideoHeight", ""); | ||
| 122 | - result.put("SourceVideoFrameRate", ""); | ||
| 123 | - result.put("SourceAudioCodecName", ""); | ||
| 124 | - result.put("SourceAudioSampleRate", ""); | ||
| 125 | - result.put("AudioEnable", ""); | ||
| 126 | - result.put("Ondemand", ""); | ||
| 127 | - result.put("InBytes", ""); | ||
| 128 | - result.put("InBitRate", ""); | ||
| 129 | - result.put("OutBytes", ""); | ||
| 130 | - result.put("NumOutputs", ""); | ||
| 131 | - result.put("CascadeSize", ""); | ||
| 132 | - result.put("RelaySize", ""); | ||
| 133 | - result.put("ChannelPTZType", 0); | ||
| 134 | - return result; | ||
| 135 | - } else { | ||
| 136 | - logger.debug("向流媒体查询没有推流, 重新点播"); | ||
| 137 | - storager.stopPlay(streamInfo); | ||
| 138 | -// streamInfo = cmder.playStreamCmd(device, code); | ||
| 139 | - } | ||
| 140 | - } | ||
| 141 | - | ||
| 142 | - if (logger.isDebugEnabled()) { | ||
| 143 | - logger.debug(String.format("设备预览 API调用,deviceId:%s ,channelId:%s",serial, code)); | ||
| 144 | - logger.debug("设备预览 API调用,ssrc:"+streamInfo.getSsrc()+",ZLMedia streamId:"+Integer.toHexString(Integer.parseInt(streamInfo.getSsrc()))); | 103 | + resultDeferredResult.setResult(result); |
| 145 | } | 104 | } |
| 146 | - boolean lockFlag = true; | ||
| 147 | - long startTime = System.currentTimeMillis(); | ||
| 148 | - while (lockFlag) { | ||
| 149 | - try { | ||
| 150 | - if (System.currentTimeMillis() - startTime > 10 * 1000) { | ||
| 151 | - storager.stopPlay(streamInfo); | ||
| 152 | - logger.info("播放等待超时"); | ||
| 153 | - JSONObject result = new JSONObject(); | ||
| 154 | - result.put("error","timeout"); | ||
| 155 | - return result; | ||
| 156 | - } else { | 105 | + DeferredResult<ResponseEntity<String>> play = playController.play(serial, code); |
| 157 | 106 | ||
| 158 | - StreamInfo streamInfoNow = storager.queryPlayByDevice(serial, code); | ||
| 159 | - logger.debug("正在向流媒体查询"); | ||
| 160 | - if (streamInfoNow != null && streamInfoNow.getFlv() != null) { | ||
| 161 | - streamInfo = streamInfoNow; | ||
| 162 | - logger.debug("向流媒体查询到: " + streamInfoNow.getRtsp()); | ||
| 163 | - lockFlag = false; | ||
| 164 | - continue; | ||
| 165 | - } else { | ||
| 166 | - Thread.sleep(2000); | ||
| 167 | - continue; | ||
| 168 | - } | ||
| 169 | - } | ||
| 170 | - } catch (InterruptedException e) { | ||
| 171 | - e.printStackTrace(); | ||
| 172 | - } | ||
| 173 | - } | ||
| 174 | - if(streamInfo!=null) { | 107 | + play.setResultHandler((Object o)->{ |
| 108 | + ResponseEntity<String> responseEntity = (ResponseEntity)o; | ||
| 109 | + StreamInfo streamInfo = JSON.parseObject(responseEntity.getBody(), StreamInfo.class); | ||
| 175 | JSONObject result = new JSONObject(); | 110 | JSONObject result = new JSONObject(); |
| 176 | - result.put("StreamID", streamInfo.getSsrc()); | 111 | + result.put("StreamID", streamInfo.getStreamId()); |
| 177 | result.put("DeviceID", device.getDeviceId()); | 112 | result.put("DeviceID", device.getDeviceId()); |
| 178 | result.put("ChannelID", code); | 113 | result.put("ChannelID", code); |
| 179 | result.put("ChannelName", deviceChannel.getName()); | 114 | result.put("ChannelName", deviceChannel.getName()); |
| @@ -203,13 +138,9 @@ public class ApiStreamController { | @@ -203,13 +138,9 @@ public class ApiStreamController { | ||
| 203 | result.put("CascadeSize", ""); | 138 | result.put("CascadeSize", ""); |
| 204 | result.put("RelaySize", ""); | 139 | result.put("RelaySize", ""); |
| 205 | result.put("ChannelPTZType", 0); | 140 | result.put("ChannelPTZType", 0); |
| 206 | - return result; | ||
| 207 | - } else { | ||
| 208 | - logger.warn("设备预览API调用失败!"); | ||
| 209 | - JSONObject result = new JSONObject(); | ||
| 210 | - result.put("error","调用失败"); | ||
| 211 | - return result; | ||
| 212 | - } | 141 | + resultDeferredResult.setResult(result); |
| 142 | + }); | ||
| 143 | + return resultDeferredResult; | ||
| 213 | } | 144 | } |
| 214 | 145 | ||
| 215 | /** | 146 | /** |
| @@ -228,14 +159,15 @@ public class ApiStreamController { | @@ -228,14 +159,15 @@ public class ApiStreamController { | ||
| 228 | @RequestParam(required = false)String check_outputs | 159 | @RequestParam(required = false)String check_outputs |
| 229 | 160 | ||
| 230 | ){ | 161 | ){ |
| 231 | - StreamInfo streamInfo = storager.queryPlayByDevice(serial, code); | 162 | + |
| 163 | + StreamInfo streamInfo = redisCatchStorage.queryPlayByDevice(serial, code); | ||
| 232 | if (streamInfo == null) { | 164 | if (streamInfo == null) { |
| 233 | JSONObject result = new JSONObject(); | 165 | JSONObject result = new JSONObject(); |
| 234 | result.put("error","未找到流信息"); | 166 | result.put("error","未找到流信息"); |
| 235 | return result; | 167 | return result; |
| 236 | } | 168 | } |
| 237 | - cmder.streamByeCmd(streamInfo.getSsrc()); | ||
| 238 | - storager.stopPlay(streamInfo); | 169 | + cmder.streamByeCmd(streamInfo.getStreamId()); |
| 170 | + redisCatchStorage.stopPlay(streamInfo); | ||
| 239 | return null; | 171 | return null; |
| 240 | } | 172 | } |
| 241 | 173 |
src/main/resources/application-dev.yml
| @@ -20,12 +20,20 @@ spring: | @@ -20,12 +20,20 @@ spring: | ||
| 20 | timeout: 10000 | 20 | timeout: 10000 |
| 21 | # [不可用] jdbc数据库配置, 暂不支持 | 21 | # [不可用] jdbc数据库配置, 暂不支持 |
| 22 | datasource: | 22 | datasource: |
| 23 | + # name: eiot | ||
| 24 | + # url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true | ||
| 25 | + # username: | ||
| 26 | + # password: | ||
| 27 | + # type: com.alibaba.druid.pool.DruidDataSource | ||
| 28 | + # driver-class-name: com.mysql.jdbc.Driver | ||
| 23 | name: eiot | 29 | name: eiot |
| 24 | - url: jdbc:mysql://127.0.0.1:3306/eiot?useUnicode=true&characterEncoding=UTF8&rewriteBatchedStatements=true | 30 | + url: jdbc:sqlite::resource:wvp.sqlite |
| 25 | username: | 31 | username: |
| 26 | password: | 32 | password: |
| 27 | type: com.alibaba.druid.pool.DruidDataSource | 33 | type: com.alibaba.druid.pool.DruidDataSource |
| 28 | - driver-class-name: com.mysql.jdbc.Driver | 34 | + driver-class-name: org.sqlite.JDBC |
| 35 | + max-active: 1 | ||
| 36 | + min-idle: 1 | ||
| 29 | 37 | ||
| 30 | # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 | 38 | # [可选] WVP监听的HTTP端口, 网页和接口调用都是这个端口 |
| 31 | server: | 39 | server: |
| @@ -34,18 +42,18 @@ server: | @@ -34,18 +42,18 @@ server: | ||
| 34 | # 作为28181服务器的配置 | 42 | # 作为28181服务器的配置 |
| 35 | sip: | 43 | sip: |
| 36 | # [必须修改] 本机的IP, 必须是网卡上的IP | 44 | # [必须修改] 本机的IP, 必须是网卡上的IP |
| 37 | - ip: 192.168.0.100 | 45 | + ip: 192.168.1.44 |
| 38 | # [可选] 28181服务监听的端口 | 46 | # [可选] 28181服务监听的端口 |
| 39 | port: 5060 | 47 | port: 5060 |
| 40 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) | 48 | # 根据国标6.1.2中规定,domain宜采用ID统一编码的前十位编码。国标附录D中定义前8位为中心编码(由省级、市级、区级、基层编号组成,参照GB/T 2260-2007) |
| 41 | # 后两位为行业编码,定义参照附录D.3 | 49 | # 后两位为行业编码,定义参照附录D.3 |
| 42 | # 3701020049标识山东济南历下区 信息行业接入 | 50 | # 3701020049标识山东济南历下区 信息行业接入 |
| 43 | # [可选] | 51 | # [可选] |
| 44 | - domain: 4401020049 | 52 | + domain: 3402000000 |
| 45 | # [可选] | 53 | # [可选] |
| 46 | - id: 44010200492000000001 | 54 | + id: 34020000002000000001 |
| 47 | # [可选] 默认设备认证密码,后续扩展使用设备单独密码 | 55 | # [可选] 默认设备认证密码,后续扩展使用设备单独密码 |
| 48 | - password: admin123 | 56 | + password: 12345678 |
| 49 | 57 | ||
| 50 | # 登陆的用户名密码 | 58 | # 登陆的用户名密码 |
| 51 | auth: | 59 | auth: |
| @@ -57,7 +65,7 @@ auth: | @@ -57,7 +65,7 @@ auth: | ||
| 57 | #zlm服务器配置 | 65 | #zlm服务器配置 |
| 58 | media: | 66 | media: |
| 59 | # [必须修改] zlm服务器的内网IP | 67 | # [必须修改] zlm服务器的内网IP |
| 60 | - ip: 192.168.0.100 | 68 | + ip: 192.168.1.44 |
| 61 | # [可选] zlm服务器的公网IP, 内网部署置空即可 | 69 | # [可选] zlm服务器的公网IP, 内网部署置空即可 |
| 62 | wanIp: | 70 | wanIp: |
| 63 | # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip | 71 | # [可选] zlm服务器的hook所使用的IP, 默认使用sip.ip |
| @@ -69,12 +77,12 @@ media: | @@ -69,12 +77,12 @@ media: | ||
| 69 | # [可选] zlm服务器的hook.admin_params=secret | 77 | # [可选] zlm服务器的hook.admin_params=secret |
| 70 | secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc | 78 | secret: 035c73f7-bb6b-4889-a715-d9eb2d1925cc |
| 71 | # [可选] zlm服务器的general.streamNoneReaderDelayMS | 79 | # [可选] zlm服务器的general.streamNoneReaderDelayMS |
| 72 | - streamNoneReaderDelayMS: 18000 # 无人观看多久自动关闭流 | ||
| 73 | - # [可选] 关闭等待收到流编码信息后在返回, | ||
| 74 | - # 设为false可以获得更好的兼容性,保证返回后流就可以播放, | ||
| 75 | - # 设为true可以快速打开播放窗口,可以获得更好的体验 | ||
| 76 | - closeWaitRTPInfo: false | ||
| 77 | - # 启用udp多端口模式 | 80 | + streamNoneReaderDelayMS: 600000 # 无人观看多久自动关闭流, -1表示永不自动关闭,即 关闭按需拉流 |
| 81 | + # [可选] 自动点播, 使用固定流地址进行播放时,如果未点播则自动进行点播, 需要rtp.enable=true | ||
| 82 | + autoApplyPlay: true | ||
| 83 | + # [可选] 部分设备需要扩展SDP,需要打开此设置 | ||
| 84 | + seniorSdp: false | ||
| 85 | + # 启用udp多端口模式, 详细解释参考: https://github.com/xia-chu/ZLMediaKit/wiki/GB28181%E6%8E%A8%E6%B5%81 下的高阶使用 | ||
| 78 | rtp: | 86 | rtp: |
| 79 | # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 | 87 | # [可选] 是否启用udp多端口模式, 开启后会在udpPortRange范围内选择端口用于媒体流传输 |
| 80 | enable: true | 88 | enable: true |
src/main/resources/wvp.sqlite
0 → 100644
No preview for this file type
web_src/src/components/channelList.vue
| @@ -19,12 +19,12 @@ | @@ -19,12 +19,12 @@ | ||
| 19 | <el-option label="设备" value="false"></el-option> | 19 | <el-option label="设备" value="false"></el-option> |
| 20 | <el-option label="子目录" value="true"></el-option> | 20 | <el-option label="子目录" value="true"></el-option> |
| 21 | </el-select> | 21 | </el-select> |
| 22 | - 在线状态: <el-select size="mini" @change="search" v-model="online" placeholder="请选择" default-first-option> | 22 | + 在线状态: <el-select size="mini" style="margin-right: 1rem;" @change="search" v-model="online" placeholder="请选择" default-first-option> |
| 23 | <el-option label="全部" value=""></el-option> | 23 | <el-option label="全部" value=""></el-option> |
| 24 | - <el-option label="在线" value="on"></el-option> | ||
| 25 | - <el-option label="离线" value="off"></el-option> | 24 | + <el-option label="在线" value="true"></el-option> |
| 25 | + <el-option label="离线" value="false"></el-option> | ||
| 26 | </el-select> | 26 | </el-select> |
| 27 | - | 27 | + <el-checkbox size="mini" style="margin-right: 1rem; float: right;" v-model="autoList" @change="autoListChange">自动刷新</el-checkbox> |
| 28 | </div> | 28 | </div> |
| 29 | <devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer> | 29 | <devicePlayer ref="devicePlayer" v-loading="isLoging"></devicePlayer> |
| 30 | <!--设备列表--> | 30 | <!--设备列表--> |
| @@ -56,7 +56,7 @@ | @@ -56,7 +56,7 @@ | ||
| 56 | <el-button-group> | 56 | <el-button-group> |
| 57 | <!-- <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">播放</el-button> --> | 57 | <!-- <el-button size="mini" icon="el-icon-video-play" v-if="scope.row.parental == 0" @click="sendDevicePush(scope.row)">播放</el-button> --> |
| 58 | <el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> | 58 | <el-button size="mini" icon="el-icon-video-play" @click="sendDevicePush(scope.row)">播放</el-button> |
| 59 | - <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="scope.row.play" @click="stopDevicePush(scope.row)">停止</el-button> | 59 | + <el-button size="mini" icon="el-icon-switch-button" type="danger" v-if="!!scope.row.streamId" @click="stopDevicePush(scope.row)">停止</el-button> |
| 60 | <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.parental == 1" @click="changeSubchannel(scope.row)">查看</el-button> | 60 | <el-button size="mini" icon="el-icon-s-open" type="primary" v-if="scope.row.parental == 1" @click="changeSubchannel(scope.row)">查看</el-button> |
| 61 | <el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象</el-button> | 61 | <el-button size="mini" icon="el-icon-video-camera" type="primary" @click="queryRecords(scope.row)">设备录象</el-button> |
| 62 | <!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> | 62 | <!-- <el-button size="mini" @click="sendDevicePush(scope.row)">录像查询</el-button> --> |
| @@ -98,13 +98,17 @@ export default { | @@ -98,13 +98,17 @@ export default { | ||
| 98 | count: parseInt(this.$route.params.count), | 98 | count: parseInt(this.$route.params.count), |
| 99 | total: 0, | 99 | total: 0, |
| 100 | beforeUrl: "/videoList", | 100 | beforeUrl: "/videoList", |
| 101 | - isLoging: false | 101 | + isLoging: false, |
| 102 | + autoList: false | ||
| 102 | }; | 103 | }; |
| 103 | }, | 104 | }, |
| 104 | 105 | ||
| 105 | mounted() { | 106 | mounted() { |
| 106 | this.initData(); | 107 | this.initData(); |
| 107 | - this.updateLooper = setInterval(this.initData, 10000); | 108 | + if (this.autoList) { |
| 109 | + this.updateLooper = setInterval(this.initData, 1500); | ||
| 110 | + } | ||
| 111 | + | ||
| 108 | }, | 112 | }, |
| 109 | destroyed() { | 113 | destroyed() { |
| 110 | this.$destroy('videojs'); | 114 | this.$destroy('videojs'); |
| @@ -161,7 +165,7 @@ export default { | @@ -161,7 +165,7 @@ export default { | ||
| 161 | .then(function (res) { | 165 | .then(function (res) { |
| 162 | console.log(res); | 166 | console.log(res); |
| 163 | that.total = res.data.total; | 167 | that.total = res.data.total; |
| 164 | - that.deviceChannelList = res.data.data; | 168 | + that.deviceChannelList = res.data.list; |
| 165 | // 防止出现表格错位 | 169 | // 防止出现表格错位 |
| 166 | that.$nextTick(() => { | 170 | that.$nextTick(() => { |
| 167 | that.$refs.channelListTable.doLayout(); | 171 | that.$refs.channelListTable.doLayout(); |
| @@ -179,17 +183,16 @@ export default { | @@ -179,17 +183,16 @@ export default { | ||
| 179 | let deviceId = this.deviceId; | 183 | let deviceId = this.deviceId; |
| 180 | this.isLoging = true; | 184 | this.isLoging = true; |
| 181 | let channelId = itemData.channelId; | 185 | let channelId = itemData.channelId; |
| 182 | - let getEncoding = itemData.hasAudio ? '1' : '0' | ||
| 183 | - console.log("通知设备推流1:" + deviceId + " : " + channelId + ":" + getEncoding); | 186 | + console.log("通知设备推流1:" + deviceId + " : " + channelId ); |
| 184 | let that = this; | 187 | let that = this; |
| 185 | this.$axios({ | 188 | this.$axios({ |
| 186 | method: 'get', | 189 | method: 'get', |
| 187 | - url: '/api/play/' + deviceId + '/' + channelId + '?getEncoding=' + getEncoding | 190 | + url: '/api/play/' + deviceId + '/' + channelId |
| 188 | }).then(function (res) { | 191 | }).then(function (res) { |
| 189 | console.log(res.data) | 192 | console.log(res.data) |
| 190 | - let ssrc = res.data.ssrc; | 193 | + let streamId = res.data.streamId; |
| 191 | that.isLoging = false; | 194 | that.isLoging = false; |
| 192 | - if (!!ssrc) { | 195 | + if (!!streamId) { |
| 193 | // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio); | 196 | // that.$refs.devicePlayer.play(res.data, deviceId, channelId, itemData.hasAudio); |
| 194 | that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { | 197 | that.$refs.devicePlayer.openDialog("media", deviceId, channelId, { |
| 195 | streamInfo: res.data, | 198 | streamInfo: res.data, |
| @@ -212,7 +215,7 @@ export default { | @@ -212,7 +215,7 @@ export default { | ||
| 212 | var that = this; | 215 | var that = this; |
| 213 | this.$axios({ | 216 | this.$axios({ |
| 214 | method: 'post', | 217 | method: 'post', |
| 215 | - url: '/api/play/' + itemData.ssrc + '/stop' | 218 | + url: '/api/play/' + itemData.streamId + '/stop' |
| 216 | }).then(function (res) { | 219 | }).then(function (res) { |
| 217 | console.log(JSON.stringify(res)); | 220 | console.log(JSON.stringify(res)); |
| 218 | that.initData(); | 221 | that.initData(); |
| @@ -258,7 +261,7 @@ export default { | @@ -258,7 +261,7 @@ export default { | ||
| 258 | }) | 261 | }) |
| 259 | .then(function (res) { | 262 | .then(function (res) { |
| 260 | that.total = res.data.total; | 263 | that.total = res.data.total; |
| 261 | - that.deviceChannelList = res.data.data; | 264 | + that.deviceChannelList = res.data.list; |
| 262 | // 防止出现表格错位 | 265 | // 防止出现表格错位 |
| 263 | that.$nextTick(() => { | 266 | that.$nextTick(() => { |
| 264 | that.$refs.channelListTable.doLayout(); | 267 | that.$refs.channelListTable.doLayout(); |
| @@ -283,6 +286,13 @@ export default { | @@ -283,6 +286,13 @@ export default { | ||
| 283 | }).then(function (res) { | 286 | }).then(function (res) { |
| 284 | console.log(JSON.stringify(res)); | 287 | console.log(JSON.stringify(res)); |
| 285 | }); | 288 | }); |
| 289 | + }, | ||
| 290 | + autoListChange: function () { | ||
| 291 | + if (this.autoList) { | ||
| 292 | + this.updateLooper = setInterval(this.initData, 1500); | ||
| 293 | + }else{ | ||
| 294 | + window.clearInterval(this.updateLooper); | ||
| 295 | + } | ||
| 286 | } | 296 | } |
| 287 | 297 | ||
| 288 | } | 298 | } |
web_src/src/components/gb28181/devicePlayer.vue
| 1 | <template> | 1 | <template> |
| 2 | <div id="devicePlayer" v-loading="isLoging"> | 2 | <div id="devicePlayer" v-loading="isLoging"> |
| 3 | - | 3 | + |
| 4 | <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()"> | 4 | <el-dialog title="视频播放" top="0" :close-on-click-modal="false" :visible.sync="showVideoDialog" :destroy-on-close="true" @close="close()"> |
| 5 | <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> --> | 5 | <!-- <LivePlayer v-if="showVideoDialog" ref="videoPlayer" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></LivePlayer> --> |
| 6 | <player ref="videoPlayer" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></player> | 6 | <player ref="videoPlayer" :visible.sync="showVideoDialog" :videoUrl="videoUrl" :error="videoError" :message="videoError" :hasaudio="hasaudio" fluent autoplay live></player> |
| @@ -121,7 +121,7 @@ | @@ -121,7 +121,7 @@ | ||
| 121 | <p>采样率: {{item.sample_rate}}</p> | 121 | <p>采样率: {{item.sample_rate}}</p> |
| 122 | </div> | 122 | </div> |
| 123 | </div> | 123 | </div> |
| 124 | - | 124 | + |
| 125 | </div> | 125 | </div> |
| 126 | 126 | ||
| 127 | </el-tab-pane> | 127 | </el-tab-pane> |
| @@ -158,7 +158,6 @@ export default { | @@ -158,7 +158,6 @@ export default { | ||
| 158 | searchHistoryResult: [] //媒体流历史记录搜索结果 | 158 | searchHistoryResult: [] //媒体流历史记录搜索结果 |
| 159 | }, | 159 | }, |
| 160 | showVideoDialog: false, | 160 | showVideoDialog: false, |
| 161 | - ssrc: '', | ||
| 162 | streamId: '', | 161 | streamId: '', |
| 163 | convertKey: '', | 162 | convertKey: '', |
| 164 | deviceId: '', | 163 | deviceId: '', |
| @@ -210,7 +209,6 @@ export default { | @@ -210,7 +209,6 @@ export default { | ||
| 210 | this.tabActiveName = tab; | 209 | this.tabActiveName = tab; |
| 211 | this.channelId = channelId; | 210 | this.channelId = channelId; |
| 212 | this.deviceId = deviceId; | 211 | this.deviceId = deviceId; |
| 213 | - this.ssrc = ""; | ||
| 214 | this.streamId = ""; | 212 | this.streamId = ""; |
| 215 | this.videoUrl = "" | 213 | this.videoUrl = "" |
| 216 | if (!!this.$refs.videoPlayer) { | 214 | if (!!this.$refs.videoPlayer) { |
| @@ -234,11 +232,10 @@ export default { | @@ -234,11 +232,10 @@ export default { | ||
| 234 | console.log(val) | 232 | console.log(val) |
| 235 | }, | 233 | }, |
| 236 | play: function (streamInfo, hasAudio) { | 234 | play: function (streamInfo, hasAudio) { |
| 237 | - | 235 | + |
| 238 | this.hasaudio = hasAudio; | 236 | this.hasaudio = hasAudio; |
| 239 | this.isLoging = false; | 237 | this.isLoging = false; |
| 240 | this.videoUrl = streamInfo.ws_flv; | 238 | this.videoUrl = streamInfo.ws_flv; |
| 241 | - this.ssrc = streamInfo.ssrc; | ||
| 242 | this.streamId = streamInfo.streamId; | 239 | this.streamId = streamInfo.streamId; |
| 243 | this.playFromStreamInfo(false, streamInfo) | 240 | this.playFromStreamInfo(false, streamInfo) |
| 244 | }, | 241 | }, |
| @@ -248,7 +245,7 @@ export default { | @@ -248,7 +245,7 @@ export default { | ||
| 248 | this.$refs.videoPlayer.pause() | 245 | this.$refs.videoPlayer.pause() |
| 249 | that.$axios({ | 246 | that.$axios({ |
| 250 | method: 'post', | 247 | method: 'post', |
| 251 | - url: '/api/play/' + that.ssrc + '/convert' | 248 | + url: '/api/play/' + that.streamId + '/convert' |
| 252 | }).then(function (res) { | 249 | }).then(function (res) { |
| 253 | if (res.data.code == 0) { | 250 | if (res.data.code == 0) { |
| 254 | that.convertKey = res.data.key; | 251 | that.convertKey = res.data.key; |
| @@ -317,7 +314,7 @@ export default { | @@ -317,7 +314,7 @@ export default { | ||
| 317 | } | 314 | } |
| 318 | this.convertKey = '' | 315 | this.convertKey = '' |
| 319 | }, | 316 | }, |
| 320 | - | 317 | + |
| 321 | copySharedInfo: function (data) { | 318 | copySharedInfo: function (data) { |
| 322 | console.log('复制内容:' + data); | 319 | console.log('复制内容:' + data); |
| 323 | this.coverPlaying = false; | 320 | this.coverPlaying = false; |
| @@ -368,9 +365,9 @@ export default { | @@ -368,9 +365,9 @@ export default { | ||
| 368 | }, | 365 | }, |
| 369 | playRecord: function (row) { | 366 | playRecord: function (row) { |
| 370 | let that = this; | 367 | let that = this; |
| 371 | - if (that.ssrc != "") { | 368 | + if (that.streamId != "") { |
| 372 | that.stopPlayRecord(function () { | 369 | that.stopPlayRecord(function () { |
| 373 | - that.ssrc = "", | 370 | + that.streamId = "", |
| 374 | that.playRecord(row); | 371 | that.playRecord(row); |
| 375 | }) | 372 | }) |
| 376 | } else { | 373 | } else { |
| @@ -380,7 +377,7 @@ export default { | @@ -380,7 +377,7 @@ export default { | ||
| 380 | row.endTime | 377 | row.endTime |
| 381 | }).then(function (res) { | 378 | }).then(function (res) { |
| 382 | var streamInfo = res.data; | 379 | var streamInfo = res.data; |
| 383 | - that.ssrc = streamInfo.ssrc; | 380 | + that.streamId = streamInfo.streamId; |
| 384 | that.videoUrl = streamInfo.ws_flv; | 381 | that.videoUrl = streamInfo.ws_flv; |
| 385 | }); | 382 | }); |
| 386 | } | 383 | } |
| @@ -390,7 +387,7 @@ export default { | @@ -390,7 +387,7 @@ export default { | ||
| 390 | this.videoUrl = ''; | 387 | this.videoUrl = ''; |
| 391 | this.$axios({ | 388 | this.$axios({ |
| 392 | method: 'get', | 389 | method: 'get', |
| 393 | - url: '/api/playback/' + this.ssrc + '/stop' | 390 | + url: '/api/playback/' + this.streamId + '/stop' |
| 394 | }).then(function (res) { | 391 | }).then(function (res) { |
| 395 | if (callback) callback() | 392 | if (callback) callback() |
| 396 | }); | 393 | }); |
web_src/src/components/videoList.vue
| @@ -8,7 +8,7 @@ | @@ -8,7 +8,7 @@ | ||
| 8 | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> | 8 | <div style="background-color: #FFFFFF; margin-bottom: 1rem; position: relative; padding: 0.5rem; text-align: left;"> |
| 9 | <span style="font-size: 1rem; font-weight: bold;">设备列表</span> | 9 | <span style="font-size: 1rem; font-weight: bold;">设备列表</span> |
| 10 | <div style="position: absolute; right: 1rem; top: 0.3rem;"> | 10 | <div style="position: absolute; right: 1rem; top: 0.3rem;"> |
| 11 | - <el-button icon="el-icon-refresh-right" circle size="mini" @click="getDeviceList()"></el-button> | 11 | + <el-button icon="el-icon-refresh-right" circle size="mini" :loading="getDeviceListLoading" @click="getDeviceList()"></el-button> |
| 12 | </div> | 12 | </div> |
| 13 | </div> | 13 | </div> |
| 14 | <devicePlayer ref="devicePlayer"></devicePlayer> | 14 | <devicePlayer ref="devicePlayer"></devicePlayer> |
| @@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
| 21 | <el-table-column label="地址" width="180" align="center"> | 21 | <el-table-column label="地址" width="180" align="center"> |
| 22 | <template slot-scope="scope"> | 22 | <template slot-scope="scope"> |
| 23 | <div slot="reference" class="name-wrapper"> | 23 | <div slot="reference" class="name-wrapper"> |
| 24 | - <el-tag size="medium">{{ scope.row.host.address }}</el-tag> | 24 | + <el-tag size="medium">{{ scope.row.hostAddress }}</el-tag> |
| 25 | </div> | 25 | </div> |
| 26 | </template> | 26 | </template> |
| 27 | </el-table-column> | 27 | </el-table-column> |
| @@ -51,7 +51,7 @@ | @@ -51,7 +51,7 @@ | ||
| 51 | 51 | ||
| 52 | <el-table-column label="操作" width="240" align="center" fixed="right"> | 52 | <el-table-column label="操作" width="240" align="center" fixed="right"> |
| 53 | <template slot-scope="scope"> | 53 | <template slot-scope="scope"> |
| 54 | - <el-button size="mini" icon="el-icon-refresh" @click="refDevice(scope.row)">刷新通道</el-button> | 54 | + <el-button size="mini" :ref="scope.row.deviceId + 'refbtn' " icon="el-icon-refresh" @click="refDevice(scope.row)">刷新通道</el-button> |
| 55 | <el-button size="mini" icon="el-icon-s-open" type="primary" @click="showChannelList(scope.row)">查看通道</el-button> | 55 | <el-button size="mini" icon="el-icon-s-open" type="primary" @click="showChannelList(scope.row)">查看通道</el-button> |
| 56 | </template> | 56 | </template> |
| 57 | </el-table-column> | 57 | </el-table-column> |
| @@ -90,7 +90,8 @@ | @@ -90,7 +90,8 @@ | ||
| 90 | winHeight: window.innerHeight - 200, | 90 | winHeight: window.innerHeight - 200, |
| 91 | currentPage:1, | 91 | currentPage:1, |
| 92 | count:15, | 92 | count:15, |
| 93 | - total:0 | 93 | + total:0, |
| 94 | + getDeviceListLoading: false | ||
| 94 | }; | 95 | }; |
| 95 | }, | 96 | }, |
| 96 | computed: { | 97 | computed: { |
| @@ -130,7 +131,7 @@ | @@ -130,7 +131,7 @@ | ||
| 130 | }, | 131 | }, |
| 131 | getDeviceList: function() { | 132 | getDeviceList: function() { |
| 132 | let that = this; | 133 | let that = this; |
| 133 | - | 134 | + this.getDeviceListLoading = true; |
| 134 | this.$axios.get(`/api/devices`,{ | 135 | this.$axios.get(`/api/devices`,{ |
| 135 | params: { | 136 | params: { |
| 136 | page: that.currentPage - 1, | 137 | page: that.currentPage - 1, |
| @@ -139,11 +140,14 @@ | @@ -139,11 +140,14 @@ | ||
| 139 | } ) | 140 | } ) |
| 140 | .then(function (res) { | 141 | .then(function (res) { |
| 141 | console.log(res); | 142 | console.log(res); |
| 143 | + console.log(res.data.list); | ||
| 142 | that.total = res.data.total; | 144 | that.total = res.data.total; |
| 143 | - that.deviceList = res.data.data; | 145 | + that.deviceList = res.data.list; |
| 146 | + that.getDeviceListLoading = false; | ||
| 144 | }) | 147 | }) |
| 145 | .catch(function (error) { | 148 | .catch(function (error) { |
| 146 | console.log(error); | 149 | console.log(error); |
| 150 | + that.getDeviceListLoading = false; | ||
| 147 | }); | 151 | }); |
| 148 | 152 | ||
| 149 | }, | 153 | }, |
| @@ -158,17 +162,31 @@ | @@ -158,17 +162,31 @@ | ||
| 158 | refDevice: function(itemData) { | 162 | refDevice: function(itemData) { |
| 159 | ///api/devices/{deviceId}/sync | 163 | ///api/devices/{deviceId}/sync |
| 160 | console.log("刷新对应设备:" + itemData.deviceId); | 164 | console.log("刷新对应设备:" + itemData.deviceId); |
| 165 | + var that = this; | ||
| 166 | + that.$refs[itemData.deviceId + 'refbtn' ].loading = true; | ||
| 161 | this.$axios({ | 167 | this.$axios({ |
| 162 | method: 'post', | 168 | method: 'post', |
| 163 | url: '/api/devices/' + itemData.deviceId + '/sync' | 169 | url: '/api/devices/' + itemData.deviceId + '/sync' |
| 164 | }).then(function(res) { | 170 | }).then(function(res) { |
| 165 | - // console.log("刷新设备结果:"+JSON.stringify(res)); | 171 | + console.log("刷新设备结果:"+JSON.stringify(res)); |
| 172 | + if (!res.data.deviceId) { | ||
| 173 | + that.$message({ | ||
| 174 | + showClose: true, | ||
| 175 | + message: res.data, | ||
| 176 | + type: 'error' | ||
| 177 | + }); | ||
| 178 | + }else{ | ||
| 179 | + that.$message({ | ||
| 180 | + showClose: true, | ||
| 181 | + message: '请求成功', | ||
| 182 | + type: 'success' | ||
| 183 | + }); | ||
| 184 | + } | ||
| 185 | + that.initData() | ||
| 186 | + that.$refs[itemData.deviceId + 'refbtn' ].loading = false; | ||
| 166 | }).catch(function(e) { | 187 | }).catch(function(e) { |
| 167 | - that.$message({ | ||
| 168 | - showClose: true, | ||
| 169 | - message: '请求成功', | ||
| 170 | - type: 'success' | ||
| 171 | - }); | 188 | + console.error(e) |
| 189 | + that.$refs[itemData.deviceId + 'refbtn' ].loading = false; | ||
| 172 | });; | 190 | });; |
| 173 | }, | 191 | }, |
| 174 | //通知设备上传媒体流 | 192 | //通知设备上传媒体流 |