Commit e6790d88fc5b1ac33d239c0d90ce6cdea666b821

Authored by mk1990
2 parents e5413415 850f2014

Merge branch 'wvp-28181-2.0' of https://github.com/mk1990/wvp-GB28181-pro into wvp-28181-2.0

Showing 34 changed files with 368 additions and 331 deletions
README.md
@@ -106,7 +106,6 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git @@ -106,7 +106,6 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git
106 - [X] 添加RTMP视频 106 - [X] 添加RTMP视频
107 - [X] 云端录像(需要部署单独服务配合使用) 107 - [X] 云端录像(需要部署单独服务配合使用)
108 - [X] 多流媒体节点,自动选择负载最低的节点使用。 108 - [X] 多流媒体节点,自动选择负载最低的节点使用。
109 -- [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。  
110 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 109 - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。
111 110
112 [//]: # (# docker快速体验) 111 [//]: # (# docker快速体验)
@@ -101,13 +101,6 @@ @@ -101,13 +101,6 @@
101 <version>8.0.22</version> 101 <version>8.0.22</version>
102 </dependency> 102 </dependency>
103 103
104 - <!-- 添加sqlite-jdbc数据库驱动 -->  
105 - <dependency>  
106 - <groupId>org.xerial</groupId>  
107 - <artifactId>sqlite-jdbc</artifactId>  
108 - <version>3.32.3.2</version>  
109 - </dependency>  
110 -  
111 <!--Mybatis分页插件 --> 104 <!--Mybatis分页插件 -->
112 <dependency> 105 <dependency>
113 <groupId>com.github.pagehelper</groupId> 106 <groupId>com.github.pagehelper</groupId>
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
1 package com.genersoft.iot.vmp.conf; 1 package com.genersoft.iot.vmp.conf;
2 2
3 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; 3 import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask;
4 -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.CatalogResponseMessageHandler;  
5 import org.slf4j.Logger; 4 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory; 5 import org.slf4j.LoggerFactory;
7 import org.springframework.beans.factory.annotation.Autowired; 6 import org.springframework.beans.factory.annotation.Autowired;
@@ -9,25 +8,27 @@ import org.springframework.context.annotation.Bean; @@ -9,25 +8,27 @@ import org.springframework.context.annotation.Bean;
9 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; 8 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
10 import org.springframework.stereotype.Component; 9 import org.springframework.stereotype.Component;
11 10
12 -import java.util.Date; 11 +import java.time.Instant;
13 import java.util.Map; 12 import java.util.Map;
14 import java.util.Set; 13 import java.util.Set;
15 import java.util.concurrent.ConcurrentHashMap; 14 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.ScheduledFuture; 15 import java.util.concurrent.ScheduledFuture;
  16 +import java.util.concurrent.TimeUnit;
17 17
18 /** 18 /**
19 * 动态定时任务 19 * 动态定时任务
  20 + * @author lin
20 */ 21 */
21 @Component 22 @Component
22 public class DynamicTask { 23 public class DynamicTask {
23 24
24 - private Logger logger = LoggerFactory.getLogger(DynamicTask.class); 25 + private final Logger logger = LoggerFactory.getLogger(DynamicTask.class);
25 26
26 @Autowired 27 @Autowired
27 private ThreadPoolTaskScheduler threadPoolTaskScheduler; 28 private ThreadPoolTaskScheduler threadPoolTaskScheduler;
28 29
29 - private Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();  
30 - private Map<String, Runnable> runnableMap = new ConcurrentHashMap<>(); 30 + private final Map<String, ScheduledFuture<?>> futureMap = new ConcurrentHashMap<>();
  31 + private final Map<String, Runnable> runnableMap = new ConcurrentHashMap<>();
31 32
32 @Bean 33 @Bean
33 public ThreadPoolTaskScheduler threadPoolTaskScheduler() { 34 public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
@@ -47,7 +48,7 @@ public class DynamicTask { @@ -47,7 +48,7 @@ public class DynamicTask {
47 * @return 48 * @return
48 */ 49 */
49 public void startCron(String key, Runnable task, int cycleForCatalog) { 50 public void startCron(String key, Runnable task, int cycleForCatalog) {
50 - ScheduledFuture future = futureMap.get(key); 51 + ScheduledFuture<?> future = futureMap.get(key);
51 if (future != null) { 52 if (future != null) {
52 if (future.isCancelled()) { 53 if (future.isCancelled()) {
53 logger.debug("任务【{}】已存在但是关闭状态!!!", key); 54 logger.debug("任务【{}】已存在但是关闭状态!!!", key);
@@ -76,7 +77,9 @@ public class DynamicTask { @@ -76,7 +77,9 @@ public class DynamicTask {
76 */ 77 */
77 public void startDelay(String key, Runnable task, int delay) { 78 public void startDelay(String key, Runnable task, int delay) {
78 stop(key); 79 stop(key);
79 - Date starTime = new Date(System.currentTimeMillis() + delay); 80 +
  81 + // 获取执行的时刻
  82 + Instant startInstant = Instant.now().plusMillis(TimeUnit.MILLISECONDS.toMillis(delay));
80 83
81 ScheduledFuture future = futureMap.get(key); 84 ScheduledFuture future = futureMap.get(key);
82 if (future != null) { 85 if (future != null) {
@@ -88,7 +91,7 @@ public class DynamicTask { @@ -88,7 +91,7 @@ public class DynamicTask {
88 } 91 }
89 } 92 }
90 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 93 // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔
91 - future = threadPoolTaskScheduler.schedule(task, starTime); 94 + future = threadPoolTaskScheduler.schedule(task, startInstant);
92 if (future != null){ 95 if (future != null){
93 futureMap.put(key, future); 96 futureMap.put(key, future);
94 runnableMap.put(key, task); 97 runnableMap.put(key, task);
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
@@ -81,11 +81,11 @@ public class SipLayer{ @@ -81,11 +81,11 @@ public class SipLayer{
81 tcpSipProvider.setDialogErrorsAutomaticallyHandled(); 81 tcpSipProvider.setDialogErrorsAutomaticallyHandled();
82 tcpSipProvider.addSipListener(sipProcessorObserver); 82 tcpSipProvider.addSipListener(sipProcessorObserver);
83 // tcpSipProvider.setAutomaticDialogSupportEnabled(false); 83 // tcpSipProvider.setAutomaticDialogSupportEnabled(false);
84 - logger.info("Sip Server TCP 启动成功 port {" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "}"); 84 + logger.info("[Sip Server] TCP 启动成功 {}:{}", sipConfig.getMonitorIp(), sipConfig.getPort());
85 } catch (TransportNotSupportedException e) { 85 } catch (TransportNotSupportedException e) {
86 e.printStackTrace(); 86 e.printStackTrace();
87 } catch (InvalidArgumentException e) { 87 } catch (InvalidArgumentException e) {
88 - logger.error("无法使用 [ {}:{} ]作为SIP[ TCP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用" 88 + logger.error("[Sip Server] 无法使用 [ {}:{} ]作为SIP[ TCP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
89 , sipConfig.getMonitorIp(), sipConfig.getPort()); 89 , sipConfig.getMonitorIp(), sipConfig.getPort());
90 } catch (TooManyListenersException e) { 90 } catch (TooManyListenersException e) {
91 e.printStackTrace(); 91 e.printStackTrace();
@@ -108,14 +108,14 @@ public class SipLayer{ @@ -108,14 +108,14 @@ public class SipLayer{
108 } catch (TransportNotSupportedException e) { 108 } catch (TransportNotSupportedException e) {
109 e.printStackTrace(); 109 e.printStackTrace();
110 } catch (InvalidArgumentException e) { 110 } catch (InvalidArgumentException e) {
111 - logger.error("无法使用 [ {}:{} ]作为SIP[ UDP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用" 111 + logger.error("[Sip Server] 无法使用 [ {}:{} ]作为SIP[ UDP ]服务,可排查: 1. sip.monitor-ip 是否为本机网卡IP; 2. sip.port 是否已被占用"
112 , sipConfig.getMonitorIp(), sipConfig.getPort()); 112 , sipConfig.getMonitorIp(), sipConfig.getPort());
113 } catch (TooManyListenersException e) { 113 } catch (TooManyListenersException e) {
114 e.printStackTrace(); 114 e.printStackTrace();
115 } catch (ObjectInUseException e) { 115 } catch (ObjectInUseException e) {
116 e.printStackTrace(); 116 e.printStackTrace();
117 } 117 }
118 - logger.info("Sip Server UDP 启动成功 port [" + sipConfig.getMonitorIp() + ":" + sipConfig.getPort() + "]"); 118 + logger.info("[Sip Server] UDP 启动成功 {}:{}", sipConfig.getMonitorIp(), sipConfig.getPort());
119 return udpSipProvider; 119 return udpSipProvider;
120 } 120 }
121 121
src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java
@@ -27,8 +27,7 @@ package com.genersoft.iot.vmp.gb28181.auth; @@ -27,8 +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;  
31 -import java.util.Date; 30 +import java.time.Instant;
32 import java.util.Random; 31 import java.util.Random;
33 32
34 import javax.sip.address.URI; 33 import javax.sip.address.URI;
@@ -90,17 +89,12 @@ public class DigestServerAuthenticationHelper { @@ -90,17 +89,12 @@ public class DigestServerAuthenticationHelper {
90 * @return a generated nonce. 89 * @return a generated nonce.
91 */ 90 */
92 private String generateNonce() { 91 private String generateNonce() {
93 - // Get the time of day and run MD5 over it.  
94 - Date date = new Date();  
95 - long time = date.getTime(); 92 + long time = Instant.now().toEpochMilli();
96 Random rand = new Random(); 93 Random rand = new Random();
97 long pad = rand.nextLong(); 94 long pad = rand.nextLong();
98 - // String nonceString = (new Long(time)).toString()  
99 - // + (new Long(pad)).toString();  
100 String nonceString = Long.valueOf(time).toString() 95 String nonceString = Long.valueOf(time).toString()
101 + Long.valueOf(pad).toString(); 96 + Long.valueOf(pad).toString();
102 byte mdbytes[] = messageDigest.digest(nonceString.getBytes()); 97 byte mdbytes[] = messageDigest.digest(nonceString.getBytes());
103 - // Convert the mdbytes array into a hex string.  
104 return toHexString(mdbytes); 98 return toHexString(mdbytes);
105 } 99 }
106 100
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 -import java.util.Date; 3 +import java.time.Instant;
4 import java.util.List; 4 import java.util.List;
5 5
6 public class CatalogData { 6 public class CatalogData {
7 private int sn; // 命令序列号 7 private int sn; // 命令序列号
8 private int total; 8 private int total;
9 private List<DeviceChannel> channelList; 9 private List<DeviceChannel> channelList;
10 - private Date lastTime; 10 + private Instant lastTime;
11 private Device device; 11 private Device device;
12 private String errorMsg; 12 private String errorMsg;
13 13
@@ -41,11 +41,11 @@ public class CatalogData { @@ -41,11 +41,11 @@ public class CatalogData {
41 this.channelList = channelList; 41 this.channelList = channelList;
42 } 42 }
43 43
44 - public Date getLastTime() { 44 + public Instant getLastTime() {
45 return lastTime; 45 return lastTime;
46 } 46 }
47 47
48 - public void setLastTime(Date lastTime) { 48 + public void setLastTime(Instant lastTime) {
49 this.lastTime = lastTime; 49 this.lastTime = lastTime;
50 } 50 }
51 51
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
1 package com.genersoft.iot.vmp.gb28181.bean; 1 package com.genersoft.iot.vmp.gb28181.bean;
2 2
3 -  
4 -//import gov.nist.javax.sip.header.SIPDate;  
5 - 3 +import java.time.Instant;
6 import java.util.List; 4 import java.util.List;
7 5
8 /** 6 /**
@@ -21,6 +19,8 @@ public class RecordInfo { @@ -21,6 +19,8 @@ public class RecordInfo {
21 private String name; 19 private String name;
22 20
23 private int sumNum; 21 private int sumNum;
  22 +
  23 + private Instant lastTime;
24 24
25 private List<RecordItem> recordList; 25 private List<RecordItem> recordList;
26 26
@@ -71,4 +71,12 @@ public class RecordInfo { @@ -71,4 +71,12 @@ public class RecordInfo {
71 public void setSn(String sn) { 71 public void setSn(String sn) {
72 this.sn = sn; 72 this.sn = sn;
73 } 73 }
  74 +
  75 + public Instant getLastTime() {
  76 + return lastTime;
  77 + }
  78 +
  79 + public void setLastTime(Instant lastTime) {
  80 + this.lastTime = lastTime;
  81 + }
74 } 82 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordItem.java
@@ -5,7 +5,8 @@ import com.genersoft.iot.vmp.utils.DateUtil; @@ -5,7 +5,8 @@ import com.genersoft.iot.vmp.utils.DateUtil;
5 import org.jetbrains.annotations.NotNull; 5 import org.jetbrains.annotations.NotNull;
6 6
7 import java.text.ParseException; 7 import java.text.ParseException;
8 -import java.util.Date; 8 +import java.time.Instant;
  9 +import java.time.temporal.TemporalAccessor;
9 10
10 /** 11 /**
11 * @description:设备录像bean 12 * @description:设备录像bean
@@ -116,17 +117,17 @@ public class RecordItem implements Comparable&lt;RecordItem&gt;{ @@ -116,17 +117,17 @@ public class RecordItem implements Comparable&lt;RecordItem&gt;{
116 117
117 @Override 118 @Override
118 public int compareTo(@NotNull RecordItem recordItem) { 119 public int compareTo(@NotNull RecordItem recordItem) {
119 - try {  
120 - Date startTime_now = DateUtil.format.parse(startTime);  
121 - Date startTime_param = DateUtil.format.parse(recordItem.getStartTime());  
122 - if (startTime_param.compareTo(startTime_now) > 0) {  
123 - return -1;  
124 - }else {  
125 - return 1;  
126 - }  
127 - } catch (ParseException e) {  
128 - e.printStackTrace(); 120 + TemporalAccessor startTimeNow = DateUtil.formatter.parse(startTime);
  121 + TemporalAccessor startTimeParam = DateUtil.formatter.parse(recordItem.getStartTime());
  122 + Instant startTimeParamInstant = Instant.from(startTimeParam);
  123 + Instant startTimeNowInstant = Instant.from(startTimeNow);
  124 + if (startTimeNowInstant.equals(startTimeParamInstant)) {
  125 + return 0;
  126 + }else if (Instant.from(startTimeParam).isAfter(Instant.from(startTimeNow)) ) {
  127 + return -1;
  128 + }else {
  129 + return 1;
129 } 130 }
130 - return 0; 131 +
131 } 132 }
132 } 133 }
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SubscribeHolder.java
@@ -66,7 +66,6 @@ public class SubscribeHolder { @@ -66,7 +66,6 @@ public class SubscribeHolder {
66 dynamicTask.stop(taskOverdueKey); 66 dynamicTask.stop(taskOverdueKey);
67 // 添加任务处理订阅过期 67 // 添加任务处理订阅过期
68 dynamicTask.startDelay(taskOverdueKey, () -> { 68 dynamicTask.startDelay(taskOverdueKey, () -> {
69 - System.out.println("订阅过期");  
70 removeMobilePositionSubscribe(subscribeInfo.getId()); 69 removeMobilePositionSubscribe(subscribeInfo.getId());
71 }, 70 },
72 subscribeInfo.getExpires() * 1000); 71 subscribeInfo.getExpires() * 1000);
src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java
@@ -9,11 +9,14 @@ import org.springframework.stereotype.Component; @@ -9,11 +9,14 @@ import org.springframework.stereotype.Component;
9 import javax.sip.*; 9 import javax.sip.*;
10 import javax.sip.header.CallIdHeader; 10 import javax.sip.header.CallIdHeader;
11 import javax.sip.message.Response; 11 import javax.sip.message.Response;
12 -import java.util.Calendar;  
13 -import java.util.Date; 12 +import java.time.Instant;
14 import java.util.Map; 13 import java.util.Map;
15 import java.util.concurrent.ConcurrentHashMap; 14 import java.util.concurrent.ConcurrentHashMap;
  15 +import java.util.concurrent.TimeUnit;
16 16
  17 +/**
  18 + * @author lin
  19 + */
17 @Component 20 @Component
18 public class SipSubscribe { 21 public class SipSubscribe {
19 22
@@ -23,28 +26,25 @@ public class SipSubscribe { @@ -23,28 +26,25 @@ public class SipSubscribe {
23 26
24 private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>(); 27 private Map<String, SipSubscribe.Event> okSubscribes = new ConcurrentHashMap<>();
25 28
26 - private Map<String, Date> okTimeSubscribes = new ConcurrentHashMap<>();  
27 - private Map<String, Date> errorTimeSubscribes = new ConcurrentHashMap<>(); 29 + private Map<String, Instant> okTimeSubscribes = new ConcurrentHashMap<>();
  30 + private Map<String, Instant> errorTimeSubscribes = new ConcurrentHashMap<>();
28 31
29 // @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次 32 // @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次
30 -// @Scheduled(fixedRate= 100 * 60 * 60 ) 33 + // @Scheduled(fixedRate= 100 * 60 * 60 )
31 @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次 34 @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次
32 public void execute(){ 35 public void execute(){
33 logger.info("[定时任务] 清理过期的SIP订阅信息"); 36 logger.info("[定时任务] 清理过期的SIP订阅信息");
34 - Calendar calendar = Calendar.getInstance();  
35 - calendar.setTime(new Date());  
36 - calendar.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE) - 5); 37 +
  38 + Instant instant = Instant.now().minusMillis(TimeUnit.MINUTES.toMillis(5));
37 39
38 for (String key : okTimeSubscribes.keySet()) { 40 for (String key : okTimeSubscribes.keySet()) {
39 - if (okTimeSubscribes.get(key).before(calendar.getTime())){  
40 -// logger.info("[定时任务] 清理过期的订阅信息: {}", key); 41 + if (okTimeSubscribes.get(key).isBefore(instant)){
41 okSubscribes.remove(key); 42 okSubscribes.remove(key);
42 okTimeSubscribes.remove(key); 43 okTimeSubscribes.remove(key);
43 } 44 }
44 } 45 }
45 for (String key : errorTimeSubscribes.keySet()) { 46 for (String key : errorTimeSubscribes.keySet()) {
46 - if (errorTimeSubscribes.get(key).before(calendar.getTime())){  
47 -// logger.info("[定时任务] 清理过期的订阅信息: {}", key); 47 + if (errorTimeSubscribes.get(key).isBefore(instant)){
48 errorSubscribes.remove(key); 48 errorSubscribes.remove(key);
49 errorTimeSubscribes.remove(key); 49 errorTimeSubscribes.remove(key);
50 } 50 }
@@ -117,12 +117,12 @@ public class SipSubscribe { @@ -117,12 +117,12 @@ public class SipSubscribe {
117 117
118 public void addErrorSubscribe(String key, SipSubscribe.Event event) { 118 public void addErrorSubscribe(String key, SipSubscribe.Event event) {
119 errorSubscribes.put(key, event); 119 errorSubscribes.put(key, event);
120 - errorTimeSubscribes.put(key, new Date()); 120 + errorTimeSubscribes.put(key, Instant.now());
121 } 121 }
122 122
123 public void addOkSubscribe(String key, SipSubscribe.Event event) { 123 public void addOkSubscribe(String key, SipSubscribe.Event event) {
124 okSubscribes.put(key, event); 124 okSubscribes.put(key, event);
125 - okTimeSubscribes.put(key, new Date()); 125 + okTimeSubscribes.put(key, Instant.now());
126 } 126 }
127 127
128 public SipSubscribe.Event getErrorSubscribe(String key) { 128 public SipSubscribe.Event getErrorSubscribe(String key) {
src/main/java/com/genersoft/iot/vmp/gb28181/session/CatalogDataCatch.java
@@ -4,16 +4,15 @@ import com.genersoft.iot.vmp.gb28181.bean.CatalogData; @@ -4,16 +4,15 @@ import com.genersoft.iot.vmp.gb28181.bean.CatalogData;
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.bean.DeviceChannel; 5 import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel;
6 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; 6 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
7 -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.storager.IVideoManagerStorage; 7 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
10 -import com.genersoft.iot.vmp.vmanager.bean.WVPResult;  
11 import org.springframework.beans.factory.annotation.Autowired; 8 import org.springframework.beans.factory.annotation.Autowired;
12 import org.springframework.scheduling.annotation.Scheduled; 9 import org.springframework.scheduling.annotation.Scheduled;
13 import org.springframework.stereotype.Component; 10 import org.springframework.stereotype.Component;
14 11
  12 +import java.time.Instant;
15 import java.util.*; 13 import java.util.*;
16 import java.util.concurrent.ConcurrentHashMap; 14 import java.util.concurrent.ConcurrentHashMap;
  15 +import java.util.concurrent.TimeUnit;
17 16
18 @Component 17 @Component
19 public class CatalogDataCatch { 18 public class CatalogDataCatch {
@@ -21,9 +20,6 @@ public class CatalogDataCatch { @@ -21,9 +20,6 @@ public class CatalogDataCatch {
21 public static Map<String, CatalogData> data = new ConcurrentHashMap<>(); 20 public static Map<String, CatalogData> data = new ConcurrentHashMap<>();
22 21
23 @Autowired 22 @Autowired
24 - private DeferredResultHolder deferredResultHolder;  
25 -  
26 - @Autowired  
27 private IVideoManagerStorage storager; 23 private IVideoManagerStorage storager;
28 24
29 public void addReady(Device device, int sn ) { 25 public void addReady(Device device, int sn ) {
@@ -34,7 +30,7 @@ public class CatalogDataCatch { @@ -34,7 +30,7 @@ public class CatalogDataCatch {
34 catalogData.setDevice(device); 30 catalogData.setDevice(device);
35 catalogData.setSn(sn); 31 catalogData.setSn(sn);
36 catalogData.setStatus(CatalogData.CatalogDataStatus.ready); 32 catalogData.setStatus(CatalogData.CatalogDataStatus.ready);
37 - catalogData.setLastTime(new Date(System.currentTimeMillis())); 33 + catalogData.setLastTime(Instant.now());
38 data.put(device.getDeviceId(), catalogData); 34 data.put(device.getDeviceId(), catalogData);
39 } 35 }
40 } 36 }
@@ -48,7 +44,7 @@ public class CatalogDataCatch { @@ -48,7 +44,7 @@ public class CatalogDataCatch {
48 catalogData.setDevice(device); 44 catalogData.setDevice(device);
49 catalogData.setChannelList(Collections.synchronizedList(new ArrayList<>())); 45 catalogData.setChannelList(Collections.synchronizedList(new ArrayList<>()));
50 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); 46 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
51 - catalogData.setLastTime(new Date(System.currentTimeMillis())); 47 + catalogData.setLastTime(Instant.now());
52 data.put(deviceId, catalogData); 48 data.put(deviceId, catalogData);
53 }else { 49 }else {
54 // 同一个设备的通道同步请求只考虑一个,其他的直接忽略 50 // 同一个设备的通道同步请求只考虑一个,其他的直接忽略
@@ -59,7 +55,7 @@ public class CatalogDataCatch { @@ -59,7 +55,7 @@ public class CatalogDataCatch {
59 catalogData.setDevice(device); 55 catalogData.setDevice(device);
60 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); 56 catalogData.setStatus(CatalogData.CatalogDataStatus.runIng);
61 catalogData.getChannelList().addAll(deviceChannelList); 57 catalogData.getChannelList().addAll(deviceChannelList);
62 - catalogData.setLastTime(new Date(System.currentTimeMillis())); 58 + catalogData.setLastTime(Instant.now());
63 } 59 }
64 } 60 }
65 61
@@ -102,16 +98,13 @@ public class CatalogDataCatch { @@ -102,16 +98,13 @@ public class CatalogDataCatch {
102 @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时 98 @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时
103 private void timerTask(){ 99 private void timerTask(){
104 Set<String> keys = data.keySet(); 100 Set<String> keys = data.keySet();
105 - Calendar calendarBefore5S = Calendar.getInstance();  
106 - calendarBefore5S.setTime(new Date());  
107 - calendarBefore5S.set(Calendar.SECOND, calendarBefore5S.get(Calendar.SECOND) - 5);  
108 101
109 - Calendar calendarBefore30S = Calendar.getInstance();  
110 - calendarBefore30S.setTime(new Date());  
111 - calendarBefore30S.set(Calendar.SECOND, calendarBefore30S.get(Calendar.SECOND) - 30); 102 + Instant instantBefore5S = Instant.now().minusMillis(TimeUnit.SECONDS.toMillis(5));
  103 + Instant instantBefore30S = Instant.now().minusMillis(TimeUnit.SECONDS.toMillis(30));
  104 +
112 for (String deviceId : keys) { 105 for (String deviceId : keys) {
113 CatalogData catalogData = data.get(deviceId); 106 CatalogData catalogData = data.get(deviceId);
114 - if ( catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 超过五秒收不到消息任务超时, 只更新这一部分数据 107 + if ( catalogData.getLastTime().isBefore(instantBefore5S)) { // 超过五秒收不到消息任务超时, 只更新这一部分数据
115 if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) { 108 if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) {
116 storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); 109 storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList());
117 if (catalogData.getTotal() != catalogData.getChannelList().size()) { 110 if (catalogData.getTotal() != catalogData.getChannelList().size()) {
@@ -124,7 +117,7 @@ public class CatalogDataCatch { @@ -124,7 +117,7 @@ public class CatalogDataCatch {
124 } 117 }
125 catalogData.setStatus(CatalogData.CatalogDataStatus.end); 118 catalogData.setStatus(CatalogData.CatalogDataStatus.end);
126 } 119 }
127 - if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end) && catalogData.getLastTime().before(calendarBefore30S.getTime())) { // 超过三十秒,如果标记为end则删除 120 + if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.end) && catalogData.getLastTime().isBefore(instantBefore30S)) { // 超过三十秒,如果标记为end则删除
128 data.remove(deviceId); 121 data.remove(deviceId);
129 } 122 }
130 } 123 }
src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java 0 → 100644
  1 +package com.genersoft.iot.vmp.gb28181.session;
  2 +
  3 +import com.genersoft.iot.vmp.gb28181.bean.*;
  4 +import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
  5 +import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
  6 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
  7 +import org.springframework.beans.factory.annotation.Autowired;
  8 +import org.springframework.scheduling.annotation.Scheduled;
  9 +import org.springframework.stereotype.Component;
  10 +
  11 +import java.time.Instant;
  12 +import java.util.*;
  13 +import java.util.concurrent.ConcurrentHashMap;
  14 +import java.util.concurrent.TimeUnit;
  15 +
  16 +/**
  17 + * @author lin
  18 + */
  19 +@Component
  20 +public class RecordDataCatch {
  21 +
  22 + public static Map<String, RecordInfo> data = new ConcurrentHashMap<>();
  23 +
  24 + @Autowired
  25 + private DeferredResultHolder deferredResultHolder;
  26 +
  27 +
  28 + public int put(String deviceId, String sn, int sumNum, List<RecordItem> recordItems) {
  29 + String key = deviceId + sn;
  30 + RecordInfo recordInfo = data.get(key);
  31 + if (recordInfo == null) {
  32 + recordInfo = new RecordInfo();
  33 + recordInfo.setDeviceId(deviceId);
  34 + recordInfo.setSn(sn.trim());
  35 + recordInfo.setSumNum(sumNum);
  36 + recordInfo.setRecordList(Collections.synchronizedList(new ArrayList<>()));
  37 + recordInfo.setLastTime(Instant.now());
  38 + recordInfo.getRecordList().addAll(recordItems);
  39 + data.put(key, recordInfo);
  40 + }else {
  41 + // 同一个设备的通道同步请求只考虑一个,其他的直接忽略
  42 + if (!Objects.equals(sn.trim(), recordInfo.getSn())) {
  43 + return 0;
  44 + }
  45 + recordInfo.getRecordList().addAll(recordItems);
  46 + recordInfo.setLastTime(Instant.now());
  47 + }
  48 + return recordInfo.getRecordList().size();
  49 + }
  50 +
  51 + @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时
  52 + private void timerTask(){
  53 + Set<String> keys = data.keySet();
  54 + // 获取五秒前的时刻
  55 + Instant instantBefore5S = Instant.now().minusMillis(TimeUnit.SECONDS.toMillis(5));
  56 + for (String key : keys) {
  57 + RecordInfo recordInfo = data.get(key);
  58 + // 超过五秒收不到消息任务超时, 只更新这一部分数据
  59 + if ( recordInfo.getLastTime().isBefore(instantBefore5S)) {
  60 + // 处理录像数据, 返回给前端
  61 + String msgKey = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn();
  62 +
  63 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  64 + wvpResult.setCode(0);
  65 + wvpResult.setMsg("success");
  66 + // 对数据进行排序
  67 + Collections.sort(recordInfo.getRecordList());
  68 + wvpResult.setData(recordInfo);
  69 +
  70 + RequestMessage msg = new RequestMessage();
  71 + msg.setKey(msgKey);
  72 + msg.setData(wvpResult);
  73 + deferredResultHolder.invokeAllResult(msg);
  74 + data.remove(key);
  75 + }
  76 + }
  77 + }
  78 +
  79 + public boolean isComplete(String deviceId, String sn) {
  80 + RecordInfo recordInfo = data.get(deviceId + sn);
  81 + return recordInfo != null && recordInfo.getRecordList().size() == recordInfo.getSumNum();
  82 + }
  83 +
  84 + public RecordInfo getRecordInfo(String deviceId, String sn) {
  85 + return data.get(deviceId + sn);
  86 + }
  87 +
  88 + public void remove(String deviceId, String sn) {
  89 + data.remove(deviceId + sn);
  90 + }
  91 +}
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
@@ -76,8 +76,8 @@ public class VideoStreamSessionManager { @@ -76,8 +76,8 @@ public class VideoStreamSessionManager {
76 } 76 }
77 77
78 78
79 - public ClientTransaction getTransactionByStream(String deviceId, String channelId, String stream){  
80 - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); 79 + public ClientTransaction getTransaction(String deviceId, String channelId, String stream, String callId){
  80 + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, stream);
81 if (ssrcTransaction == null) { 81 if (ssrcTransaction == null) {
82 return null; 82 return null;
83 } 83 }
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/CheckForAllRecordsThread.java deleted 100644 → 0
1 -package com.genersoft.iot.vmp.gb28181.transmit.callback;  
2 -  
3 -import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;  
4 -import com.genersoft.iot.vmp.gb28181.bean.RecordItem;  
5 -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd.RecordInfoResponseMessageHandler;  
6 -import com.genersoft.iot.vmp.utils.redis.RedisUtil;  
7 -import org.slf4j.Logger;  
8 -  
9 -import java.util.ArrayList;  
10 -import java.util.Comparator;  
11 -import java.util.List;  
12 -import java.util.concurrent.TimeUnit;  
13 -  
14 -@SuppressWarnings("unchecked")  
15 -public class CheckForAllRecordsThread extends Thread {  
16 -  
17 - private String key;  
18 -  
19 - private RecordInfo recordInfo;  
20 -  
21 - private RedisUtil redis;  
22 -  
23 - private Logger logger;  
24 -  
25 - private DeferredResultHolder deferredResultHolder;  
26 -  
27 - public CheckForAllRecordsThread(String key, RecordInfo recordInfo) {  
28 - this.key = key;  
29 - this.recordInfo = recordInfo;  
30 - }  
31 -  
32 - @Override  
33 - public void run() {  
34 -  
35 - String cacheKey = this.key;  
36 -  
37 - for (long stop = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); stop > System.nanoTime();) {  
38 - List<Object> cacheKeys = redis.scan(cacheKey + "_*");  
39 - List<RecordItem> totalRecordList = new ArrayList<RecordItem>();  
40 - for (int i = 0; i < cacheKeys.size(); i++) {  
41 - totalRecordList.addAll((List<RecordItem>) redis.get(cacheKeys.get(i).toString()));  
42 - }  
43 - if (totalRecordList.size() < this.recordInfo.getSumNum()) {  
44 - logger.info("已获取" + totalRecordList.size() + "项录像数据,共" + this.recordInfo.getSumNum() + "项");  
45 - } else {  
46 - logger.info("录像数据已全部获取,共 {} 项", this.recordInfo.getSumNum());  
47 - this.recordInfo.setRecordList(totalRecordList);  
48 - for (int i = 0; i < cacheKeys.size(); i++) {  
49 - redis.del(cacheKeys.get(i).toString());  
50 - }  
51 - break;  
52 - }  
53 - }  
54 - // 自然顺序排序, 元素进行升序排列  
55 - this.recordInfo.getRecordList().sort(Comparator.naturalOrder());  
56 - RequestMessage msg = new RequestMessage();  
57 - msg.setKey(DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn());  
58 - msg.setData(recordInfo);  
59 - deferredResultHolder.invokeAllResult(msg);  
60 - logger.info("处理完成,返回结果");  
61 - RecordInfoResponseMessageHandler.threadNameList.remove(cacheKey);  
62 - }  
63 -  
64 - public void setRedis(RedisUtil redis) {  
65 - this.redis = redis;  
66 - }  
67 -  
68 - public void setDeferredResultHolder(DeferredResultHolder deferredResultHolder) {  
69 - this.deferredResultHolder = deferredResultHolder;  
70 - }  
71 -  
72 - public void setLogger(Logger logger) {  
73 - this.logger = logger;  
74 - }  
75 -  
76 -}  
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
@@ -370,7 +370,7 @@ public class SIPCommander implements ISIPCommander { @@ -370,7 +370,7 @@ public class SIPCommander implements ISIPCommander {
370 // 370 //
371 StringBuffer content = new StringBuffer(200); 371 StringBuffer content = new StringBuffer(200);
372 content.append("v=0\r\n"); 372 content.append("v=0\r\n");
373 - content.append("o="+ sipConfig.getId()+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); 373 + content.append("o="+ channelId+" 0 0 IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
374 content.append("s=Play\r\n"); 374 content.append("s=Play\r\n");
375 content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); 375 content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n");
376 content.append("t=0 0\r\n"); 376 content.append("t=0 0\r\n");
@@ -389,8 +389,7 @@ public class SIPCommander implements ISIPCommander { @@ -389,8 +389,7 @@ public class SIPCommander implements ISIPCommander {
389 content.append("a=rtpmap:126 H264/90000\r\n"); 389 content.append("a=rtpmap:126 H264/90000\r\n");
390 content.append("a=rtpmap:125 H264S/90000\r\n"); 390 content.append("a=rtpmap:125 H264S/90000\r\n");
391 content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); 391 content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
392 - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");  
393 - content.append("a=fmtp:99 profile-level-id=3\r\n"); 392 + content.append("a=rtpmap:99 H265/90000\r\n");
394 content.append("a=rtpmap:98 H264/90000\r\n"); 393 content.append("a=rtpmap:98 H264/90000\r\n");
395 content.append("a=rtpmap:97 MPEG4/90000\r\n"); 394 content.append("a=rtpmap:97 MPEG4/90000\r\n");
396 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 395 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
@@ -402,16 +401,17 @@ public class SIPCommander implements ISIPCommander { @@ -402,16 +401,17 @@ public class SIPCommander implements ISIPCommander {
402 } 401 }
403 }else { 402 }else {
404 if("TCP-PASSIVE".equals(streamMode)) { 403 if("TCP-PASSIVE".equals(streamMode)) {
405 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 404 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
406 }else if ("TCP-ACTIVE".equals(streamMode)) { 405 }else if ("TCP-ACTIVE".equals(streamMode)) {
407 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 406 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
408 }else if("UDP".equals(streamMode)) { 407 }else if("UDP".equals(streamMode)) {
409 - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); 408 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
410 } 409 }
411 content.append("a=recvonly\r\n"); 410 content.append("a=recvonly\r\n");
412 content.append("a=rtpmap:96 PS/90000\r\n"); 411 content.append("a=rtpmap:96 PS/90000\r\n");
413 content.append("a=rtpmap:98 H264/90000\r\n"); 412 content.append("a=rtpmap:98 H264/90000\r\n");
414 content.append("a=rtpmap:97 MPEG4/90000\r\n"); 413 content.append("a=rtpmap:97 MPEG4/90000\r\n");
  414 + content.append("a=rtpmap:99 H265/90000\r\n");
415 if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 415 if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式
416 content.append("a=setup:passive\r\n"); 416 content.append("a=setup:passive\r\n");
417 content.append("a=connection:new\r\n"); 417 content.append("a=connection:new\r\n");
@@ -467,7 +467,7 @@ public class SIPCommander implements ISIPCommander { @@ -467,7 +467,7 @@ public class SIPCommander implements ISIPCommander {
467 467
468 StringBuffer content = new StringBuffer(200); 468 StringBuffer content = new StringBuffer(200);
469 content.append("v=0\r\n"); 469 content.append("v=0\r\n");
470 - content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); 470 + content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
471 content.append("s=Playback\r\n"); 471 content.append("s=Playback\r\n");
472 content.append("u="+channelId+":0\r\n"); 472 content.append("u="+channelId+":0\r\n");
473 content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); 473 content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
@@ -490,8 +490,7 @@ public class SIPCommander implements ISIPCommander { @@ -490,8 +490,7 @@ public class SIPCommander implements ISIPCommander {
490 content.append("a=rtpmap:126 H264/90000\r\n"); 490 content.append("a=rtpmap:126 H264/90000\r\n");
491 content.append("a=rtpmap:125 H264S/90000\r\n"); 491 content.append("a=rtpmap:125 H264S/90000\r\n");
492 content.append("a=fmtp:125 profile-level-id=42e01e\r\n"); 492 content.append("a=fmtp:125 profile-level-id=42e01e\r\n");
493 - content.append("a=rtpmap:99 MP4V-ES/90000\r\n");  
494 - content.append("a=fmtp:99 profile-level-id=3\r\n"); 493 + content.append("a=rtpmap:99 H265/90000\r\n");
495 content.append("a=rtpmap:98 H264/90000\r\n"); 494 content.append("a=rtpmap:98 H264/90000\r\n");
496 content.append("a=rtpmap:97 MPEG4/90000\r\n"); 495 content.append("a=rtpmap:97 MPEG4/90000\r\n");
497 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 496 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
@@ -503,16 +502,17 @@ public class SIPCommander implements ISIPCommander { @@ -503,16 +502,17 @@ public class SIPCommander implements ISIPCommander {
503 } 502 }
504 }else { 503 }else {
505 if("TCP-PASSIVE".equals(streamMode)) { 504 if("TCP-PASSIVE".equals(streamMode)) {
506 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 505 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
507 }else if ("TCP-ACTIVE".equals(streamMode)) { 506 }else if ("TCP-ACTIVE".equals(streamMode)) {
508 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 507 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
509 }else if("UDP".equals(streamMode)) { 508 }else if("UDP".equals(streamMode)) {
510 - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); 509 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
511 } 510 }
512 content.append("a=recvonly\r\n"); 511 content.append("a=recvonly\r\n");
513 content.append("a=rtpmap:96 PS/90000\r\n"); 512 content.append("a=rtpmap:96 PS/90000\r\n");
514 - content.append("a=rtpmap:98 H264/90000\r\n");  
515 content.append("a=rtpmap:97 MPEG4/90000\r\n"); 513 content.append("a=rtpmap:97 MPEG4/90000\r\n");
  514 + content.append("a=rtpmap:98 H264/90000\r\n");
  515 + content.append("a=rtpmap:99 H265/90000\r\n");
516 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 516 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
517 content.append("a=setup:passive\r\n"); 517 content.append("a=setup:passive\r\n");
518 content.append("a=connection:new\r\n"); 518 content.append("a=connection:new\r\n");
@@ -577,7 +577,7 @@ public class SIPCommander implements ISIPCommander { @@ -577,7 +577,7 @@ public class SIPCommander implements ISIPCommander {
577 577
578 StringBuffer content = new StringBuffer(200); 578 StringBuffer content = new StringBuffer(200);
579 content.append("v=0\r\n"); 579 content.append("v=0\r\n");
580 - content.append("o="+sipConfig.getId()+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n"); 580 + content.append("o="+channelId+" 0 0 IN IP4 " + mediaServerItem.getSdpIp() + "\r\n");
581 content.append("s=Download\r\n"); 581 content.append("s=Download\r\n");
582 content.append("u="+channelId+":0\r\n"); 582 content.append("u="+channelId+":0\r\n");
583 content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); 583 content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n");
@@ -613,16 +613,17 @@ public class SIPCommander implements ISIPCommander { @@ -613,16 +613,17 @@ public class SIPCommander implements ISIPCommander {
613 } 613 }
614 }else { 614 }else {
615 if("TCP-PASSIVE".equals(streamMode)) { 615 if("TCP-PASSIVE".equals(streamMode)) {
616 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 616 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
617 }else if ("TCP-ACTIVE".equals(streamMode)) { 617 }else if ("TCP-ACTIVE".equals(streamMode)) {
618 - content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 98 97\r\n"); 618 + content.append("m=video "+ ssrcInfo.getPort() +" TCP/RTP/AVP 96 97 98 99\r\n");
619 }else if("UDP".equals(streamMode)) { 619 }else if("UDP".equals(streamMode)) {
620 - content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 98 97\r\n"); 620 + content.append("m=video "+ ssrcInfo.getPort() +" RTP/AVP 96 97 98 99\r\n");
621 } 621 }
622 content.append("a=recvonly\r\n"); 622 content.append("a=recvonly\r\n");
623 content.append("a=rtpmap:96 PS/90000\r\n"); 623 content.append("a=rtpmap:96 PS/90000\r\n");
624 - content.append("a=rtpmap:98 H264/90000\r\n");  
625 content.append("a=rtpmap:97 MPEG4/90000\r\n"); 624 content.append("a=rtpmap:97 MPEG4/90000\r\n");
  625 + content.append("a=rtpmap:98 H264/90000\r\n");
  626 + content.append("a=rtpmap:99 H265/90000\r\n");
626 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 627 if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式
627 content.append("a=setup:passive\r\n"); 628 content.append("a=setup:passive\r\n");
628 content.append("a=connection:new\r\n"); 629 content.append("a=connection:new\r\n");
@@ -651,6 +652,17 @@ public class SIPCommander implements ISIPCommander { @@ -651,6 +652,17 @@ public class SIPCommander implements ISIPCommander {
651 (MediaServerItem mediaServerItemInUse, JSONObject json)->{ 652 (MediaServerItem mediaServerItemInUse, JSONObject json)->{
652 hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); 653 hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream()));
653 subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey); 654 subscribe.removeSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey);
  655 + subscribeKey.put("regist", false);
  656 + subscribeKey.put("schema", "rtmp");
  657 + // 添加流注销的订阅,注销了后向设备发送bye
  658 + subscribe.addSubscribe(ZLMHttpHookSubscribe.HookType.on_stream_changed, subscribeKey,
  659 + (MediaServerItem mediaServerItemForEnd, JSONObject jsonForEnd)->{
  660 + ClientTransaction transaction = streamSession.getTransaction(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
  661 + if (transaction != null) {
  662 + logger.info("[录像]下载结束, 发送BYE");
  663 + streamByeCmd(device.getDeviceId(), channelId, ssrcInfo.getStream(), callIdHeader.getCallId());
  664 + }
  665 + });
654 }); 666 });
655 667
656 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc()); 668 Request request = headerProvider.createPlaybackInviteRequest(device, channelId, content.toString(), null, "fromplybck" + tm, null, callIdHeader, ssrcInfo.getSsrc());
@@ -683,10 +695,10 @@ public class SIPCommander implements ISIPCommander { @@ -683,10 +695,10 @@ public class SIPCommander implements ISIPCommander {
683 @Override 695 @Override
684 public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) { 696 public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) {
685 try { 697 try {
686 - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream);  
687 - ClientTransaction transaction = streamSession.getTransactionByStream(deviceId, channelId, stream); 698 + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, callId, stream);
  699 + ClientTransaction transaction = streamSession.getTransaction(deviceId, channelId, stream, callId);
688 700
689 - if (transaction == null) { 701 + if (transaction == null ) {
690 logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); 702 logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId);
691 SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>(); 703 SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>();
692 if (okEvent != null) { 704 if (okEvent != null) {
@@ -1663,6 +1675,7 @@ public class SIPCommander implements ISIPCommander { @@ -1663,6 +1675,7 @@ public class SIPCommander implements ISIPCommander {
1663 sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { 1675 sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> {
1664 errorEvent.response(eventResult); 1676 errorEvent.response(eventResult);
1665 sipSubscribe.removeErrorSubscribe(eventResult.callId); 1677 sipSubscribe.removeErrorSubscribe(eventResult.callId);
  1678 + sipSubscribe.removeOkSubscribe(eventResult.callId);
1666 })); 1679 }));
1667 } 1680 }
1668 // 添加订阅 1681 // 添加订阅
@@ -1670,6 +1683,7 @@ public class SIPCommander implements ISIPCommander { @@ -1670,6 +1683,7 @@ public class SIPCommander implements ISIPCommander {
1670 sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{ 1683 sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{
1671 okEvent.response(eventResult); 1684 okEvent.response(eventResult);
1672 sipSubscribe.removeOkSubscribe(eventResult.callId); 1685 sipSubscribe.removeOkSubscribe(eventResult.callId);
  1686 + sipSubscribe.removeErrorSubscribe(eventResult.callId);
1673 }); 1687 });
1674 } 1688 }
1675 1689
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
@@ -40,7 +40,7 @@ import javax.sip.header.CallIdHeader; @@ -40,7 +40,7 @@ import javax.sip.header.CallIdHeader;
40 import javax.sip.message.Request; 40 import javax.sip.message.Request;
41 import javax.sip.message.Response; 41 import javax.sip.message.Response;
42 import java.text.ParseException; 42 import java.text.ParseException;
43 -import java.util.Date; 43 +import java.time.Instant;
44 import java.util.Vector; 44 import java.util.Vector;
45 45
46 /** 46 /**
@@ -180,16 +180,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -180,16 +180,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
180 180
181 Long startTime = null; 181 Long startTime = null;
182 Long stopTime = null; 182 Long stopTime = null;
183 - Date start = null;  
184 - Date end = null; 183 + Instant start = null;
  184 + Instant end = null;
185 if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) { 185 if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) {
186 TimeDescriptionImpl timeDescription = (TimeDescriptionImpl)(sdp.getTimeDescriptions(false).get(0)); 186 TimeDescriptionImpl timeDescription = (TimeDescriptionImpl)(sdp.getTimeDescriptions(false).get(0));
187 TimeField startTimeFiled = (TimeField)timeDescription.getTime(); 187 TimeField startTimeFiled = (TimeField)timeDescription.getTime();
188 startTime = startTimeFiled.getStartTime(); 188 startTime = startTimeFiled.getStartTime();
189 stopTime = startTimeFiled.getStopTime(); 189 stopTime = startTimeFiled.getStopTime();
190 190
191 - start = new Date(startTime*1000);  
192 - end = new Date(stopTime*1000); 191 + start = Instant.ofEpochMilli(startTime*1000);
  192 + end = Instant.ofEpochMilli(stopTime*1000);
193 } 193 }
194 // 获取支持的格式 194 // 获取支持的格式
195 Vector mediaDescriptions = sdp.getMediaDescriptions(true); 195 Vector mediaDescriptions = sdp.getMediaDescriptions(true);
@@ -331,12 +331,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -331,12 +331,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
331 sendRtpItem.setApp("rtp"); 331 sendRtpItem.setApp("rtp");
332 if ("Playback".equals(sessionName)) { 332 if ("Playback".equals(sessionName)) {
333 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); 333 sendRtpItem.setPlayType(InviteStreamType.PLAYBACK);
334 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); 334 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true, true);
335 sendRtpItem.setStreamId(ssrcInfo.getStream()); 335 sendRtpItem.setStreamId(ssrcInfo.getStream());
336 // 写入redis, 超时时回复 336 // 写入redis, 超时时回复
337 redisCatchStorage.updateSendRTPSever(sendRtpItem); 337 redisCatchStorage.updateSendRTPSever(sendRtpItem);
338 - playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.format.format(start),  
339 - DateUtil.format.format(end), null, result -> { 338 + playService.playBack(mediaServerItem, ssrcInfo, device.getDeviceId(), channelId, DateUtil.formatter.format(start),
  339 + DateUtil.formatter.format(end), null, result -> {
340 if (result.getCode() != 0){ 340 if (result.getCode() != 0){
341 logger.warn("录像回放失败"); 341 logger.warn("录像回放失败");
342 if (result.getEvent() != null) { 342 if (result.getEvent() != null) {
@@ -372,7 +372,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements @@ -372,7 +372,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements
372 if (mediaServerItem.isRtpEnable()) { 372 if (mediaServerItem.isRtpEnable()) {
373 streamId = String.format("%s_%s", device.getDeviceId(), channelId); 373 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
374 } 374 }
375 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, true); 375 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, true, false);
376 sendRtpItem.setStreamId(ssrcInfo.getStream()); 376 sendRtpItem.setStreamId(ssrcInfo.getStream());
377 // 写入redis, 超时时回复 377 // 写入redis, 超时时回复
378 redisCatchStorage.updateSendRTPSever(sendRtpItem); 378 redisCatchStorage.updateSendRTPSever(sendRtpItem);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
@@ -81,7 +81,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -81,7 +81,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
81 try { 81 try {
82 RequestEventExt evtExt = (RequestEventExt) evt; 82 RequestEventExt evtExt = (RequestEventExt) evt;
83 String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); 83 String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
84 - logger.info("[{}] 收到注册请求,开始处理", requestAddress); 84 + logger.info("[注册请求] 开始处理: {}", requestAddress);
85 Request request = evt.getRequest(); 85 Request request = evt.getRequest();
86 ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); 86 ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME);
87 Response response = null; 87 Response response = null;
@@ -95,7 +95,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -95,7 +95,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
95 95
96 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); 96 AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
97 if (authHead == null) { 97 if (authHead == null) {
98 - logger.info("[{}] 未携带授权头 回复401", requestAddress); 98 + logger.info("[注册请求] 未携带授权头 回复401: {}", requestAddress);
99 response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); 99 response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
100 new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); 100 new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
101 sendResponse(evt, response); 101 sendResponse(evt, response);
@@ -111,7 +111,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -111,7 +111,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
111 // 注册失败 111 // 注册失败
112 response = getMessageFactory().createResponse(Response.FORBIDDEN, request); 112 response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
113 response.setReasonPhrase("wrong password"); 113 response.setReasonPhrase("wrong password");
114 - logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress); 114 + logger.info("[注册请求] 密码/SIP服务器ID错误, 回复403: {}", requestAddress);
115 sendResponse(evt, response); 115 sendResponse(evt, response);
116 return; 116 return;
117 } 117 }
@@ -176,11 +176,11 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -176,11 +176,11 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
176 // 注册成功 176 // 注册成功
177 // 保存到redis 177 // 保存到redis
178 if (registerFlag) { 178 if (registerFlag) {
179 - logger.info("[{}] 注册成功! deviceId:" + deviceId, requestAddress); 179 + logger.info("[注册成功] deviceId: {}->{}", deviceId, requestAddress);
180 device.setRegisterTime(DateUtil.getNow()); 180 device.setRegisterTime(DateUtil.getNow());
181 deviceService.online(device); 181 deviceService.online(device);
182 } else { 182 } else {
183 - logger.info("[{}] 注销成功! deviceId:" + deviceId, requestAddress); 183 + logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress);
184 deviceService.offline(deviceId); 184 deviceService.offline(deviceId);
185 } 185 }
186 } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { 186 } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) {
@@ -192,7 +192,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen @@ -192,7 +192,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
192 private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException { 192 private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException {
193 ServerTransaction serverTransaction = getServerTransaction(evt); 193 ServerTransaction serverTransaction = getServerTransaction(evt);
194 if (serverTransaction == null) { 194 if (serverTransaction == null) {
195 - logger.warn("回复失败:{}", response); 195 + logger.warn("[回复失败]:{}", response);
196 return; 196 return;
197 } 197 }
198 serverTransaction.sendResponse(response); 198 serverTransaction.sendResponse(response);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
@@ -24,8 +24,6 @@ import javax.sip.SipException; @@ -24,8 +24,6 @@ import javax.sip.SipException;
24 import javax.sip.header.ViaHeader; 24 import javax.sip.header.ViaHeader;
25 import javax.sip.message.Response; 25 import javax.sip.message.Response;
26 import java.text.ParseException; 26 import java.text.ParseException;
27 -import java.util.Calendar;  
28 -import java.util.Date;  
29 27
30 @Component 28 @Component
31 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { 29 public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java
@@ -60,10 +60,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i @@ -60,10 +60,9 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i
60 CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); 60 CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME);
61 String NotifyType =getText(rootElement, "NotifyType"); 61 String NotifyType =getText(rootElement, "NotifyType");
62 if (NotifyType.equals("121")){ 62 if (NotifyType.equals("121")){
63 - logger.info("媒体播放完毕,通知关流"); 63 + logger.info("[录像流]推送完毕,收到关流通知");
64 String channelId =getText(rootElement, "DeviceID"); 64 String channelId =getText(rootElement, "DeviceID");
65 -// redisCatchStorage.stopPlayback(device.getDeviceId(), channelId, null, callIdHeader.getCallId());  
66 -// redisCatchStorage.stopDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); 65 + // 查询是设备
67 StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); 66 StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId());
68 // 设置进度100% 67 // 设置进度100%
69 streamInfo.setProgress(1); 68 streamInfo.setProgress(1);
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java
@@ -5,14 +5,14 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; @@ -5,14 +5,14 @@ import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
5 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; 5 import com.genersoft.iot.vmp.gb28181.bean.RecordInfo;
6 import com.genersoft.iot.vmp.gb28181.bean.RecordItem; 6 import com.genersoft.iot.vmp.gb28181.bean.RecordItem;
7 import com.genersoft.iot.vmp.gb28181.event.EventPublisher; 7 import com.genersoft.iot.vmp.gb28181.event.EventPublisher;
8 -import com.genersoft.iot.vmp.gb28181.transmit.callback.CheckForAllRecordsThread; 8 +import com.genersoft.iot.vmp.gb28181.session.RecordDataCatch;
9 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; 9 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
10 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 10 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; 11 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; 12 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler;
13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; 13 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler;
14 import com.genersoft.iot.vmp.utils.DateUtil; 14 import com.genersoft.iot.vmp.utils.DateUtil;
15 -import com.genersoft.iot.vmp.utils.redis.RedisUtil; 15 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
16 import org.dom4j.DocumentException; 16 import org.dom4j.DocumentException;
17 import org.dom4j.Element; 17 import org.dom4j.Element;
18 import org.slf4j.Logger; 18 import org.slf4j.Logger;
@@ -20,19 +20,20 @@ import org.slf4j.LoggerFactory; @@ -20,19 +20,20 @@ import org.slf4j.LoggerFactory;
20 import org.springframework.beans.factory.InitializingBean; 20 import org.springframework.beans.factory.InitializingBean;
21 import org.springframework.beans.factory.annotation.Autowired; 21 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.stereotype.Component; 22 import org.springframework.stereotype.Component;
  23 +import org.springframework.util.StringUtils;
23 24
24 import javax.sip.InvalidArgumentException; 25 import javax.sip.InvalidArgumentException;
25 import javax.sip.RequestEvent; 26 import javax.sip.RequestEvent;
26 import javax.sip.SipException; 27 import javax.sip.SipException;
27 import javax.sip.message.Response; 28 import javax.sip.message.Response;
28 import java.text.ParseException; 29 import java.text.ParseException;
29 -import java.util.ArrayList;  
30 -import java.util.Iterator;  
31 -import java.util.List;  
32 -import java.util.UUID; 30 +import java.util.*;
33 31
34 import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; 32 import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText;
35 33
  34 +/**
  35 + * @author lin
  36 + */
36 @Component 37 @Component
37 public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { 38 public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler {
38 39
@@ -45,11 +46,13 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -45,11 +46,13 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
45 private ResponseMessageHandler responseMessageHandler; 46 private ResponseMessageHandler responseMessageHandler;
46 47
47 @Autowired 48 @Autowired
48 - private RedisUtil redis; 49 + private RecordDataCatch recordDataCatch;
49 50
50 @Autowired 51 @Autowired
51 private DeferredResultHolder deferredResultHolder; 52 private DeferredResultHolder deferredResultHolder;
52 53
  54 +
  55 +
53 @Autowired 56 @Autowired
54 private EventPublisher eventPublisher; 57 private EventPublisher eventPublisher;
55 58
@@ -66,32 +69,22 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -66,32 +69,22 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
66 responseAck(evt, Response.OK); 69 responseAck(evt, Response.OK);
67 70
68 rootElement = getRootElement(evt, device.getCharset()); 71 rootElement = getRootElement(evt, device.getCharset());
69 - String uuid = UUID.randomUUID().toString().replace("-", "");  
70 - RecordInfo recordInfo = new RecordInfo();  
71 String sn = getText(rootElement, "SN"); 72 String sn = getText(rootElement, "SN");
72 - String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + device.getDeviceId() + sn;  
73 - recordInfo.setDeviceId(device.getDeviceId());  
74 - recordInfo.setSn(sn);  
75 - recordInfo.setName(getText(rootElement, "Name"));  
76 - if (getText(rootElement, "SumNum") == null || getText(rootElement, "SumNum") == "") {  
77 - recordInfo.setSumNum(0);  
78 - } else {  
79 - recordInfo.setSumNum(Integer.parseInt(getText(rootElement, "SumNum"))); 73 +
  74 + String sumNumStr = getText(rootElement, "SumNum");
  75 + int sumNum = 0;
  76 + if (!StringUtils.isEmpty(sumNumStr)) {
  77 + sumNum = Integer.parseInt(sumNumStr);
80 } 78 }
81 Element recordListElement = rootElement.element("RecordList"); 79 Element recordListElement = rootElement.element("RecordList");
82 - if (recordListElement == null || recordInfo.getSumNum() == 0) { 80 + if (recordListElement == null || sumNum == 0) {
83 logger.info("无录像数据"); 81 logger.info("无录像数据");
84 - eventPublisher.recordEndEventPush(recordInfo);  
85 - RequestMessage msg = new RequestMessage();  
86 - msg.setKey(key);  
87 - msg.setData(recordInfo);  
88 - deferredResultHolder.invokeAllResult(msg); 82 + recordDataCatch.put(device.getDeviceId(), sn, sumNum, new ArrayList<>());
  83 + releaseRequest(device.getDeviceId(), sn);
89 } else { 84 } else {
90 Iterator<Element> recordListIterator = recordListElement.elementIterator(); 85 Iterator<Element> recordListIterator = recordListElement.elementIterator();
91 - List<RecordItem> recordList = new ArrayList<RecordItem>();  
92 if (recordListIterator != null) { 86 if (recordListIterator != null) {
93 - RecordItem record = new RecordItem();  
94 - logger.info("处理录像列表数据..."); 87 + List<RecordItem> recordList = new ArrayList<>();
95 // 遍历DeviceList 88 // 遍历DeviceList
96 while (recordListIterator.hasNext()) { 89 while (recordListIterator.hasNext()) {
97 Element itemRecord = recordListIterator.next(); 90 Element itemRecord = recordListIterator.next();
@@ -100,43 +93,31 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -100,43 +93,31 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
100 logger.info("记录为空,下一个..."); 93 logger.info("记录为空,下一个...");
101 continue; 94 continue;
102 } 95 }
103 - record = new RecordItem(); 96 + RecordItem record = new RecordItem();
104 record.setDeviceId(getText(itemRecord, "DeviceID")); 97 record.setDeviceId(getText(itemRecord, "DeviceID"));
105 record.setName(getText(itemRecord, "Name")); 98 record.setName(getText(itemRecord, "Name"));
106 record.setFilePath(getText(itemRecord, "FilePath")); 99 record.setFilePath(getText(itemRecord, "FilePath"));
107 record.setFileSize(getText(itemRecord, "FileSize")); 100 record.setFileSize(getText(itemRecord, "FileSize"));
108 record.setAddress(getText(itemRecord, "Address")); 101 record.setAddress(getText(itemRecord, "Address"));
109 - record.setStartTime(  
110 - DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "StartTime")));  
111 - record.setEndTime(  
112 - DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(getText(itemRecord, "EndTime"))); 102 +
  103 + String startTimeStr = getText(itemRecord, "StartTime");
  104 + record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr));
  105 +
  106 + String endTimeStr = getText(itemRecord, "EndTime");
  107 + record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr));
  108 +
113 record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 109 record.setSecrecy(itemRecord.element("Secrecy") == null ? 0
114 : Integer.parseInt(getText(itemRecord, "Secrecy"))); 110 : Integer.parseInt(getText(itemRecord, "Secrecy")));
115 record.setType(getText(itemRecord, "Type")); 111 record.setType(getText(itemRecord, "Type"));
116 record.setRecorderId(getText(itemRecord, "RecorderID")); 112 record.setRecorderId(getText(itemRecord, "RecorderID"));
117 recordList.add(record); 113 recordList.add(record);
118 } 114 }
119 - recordInfo.setRecordList(recordList); 115 + int count = recordDataCatch.put(device.getDeviceId(), sn, sumNum, recordList);
  116 + logger.info("[国标录像], {}->{}: {}/{}", device.getDeviceId(), sn, count, sumNum);
120 } 117 }
121 - eventPublisher.recordEndEventPush(recordInfo);  
122 - // 改用单独线程统计已获取录像文件数量,避免多包并行分别统计不完整的问题  
123 - String cacheKey = CACHE_RECORDINFO_KEY + device.getDeviceId() + sn;  
124 - redis.set(cacheKey + "_" + uuid, recordList, 90);  
125 - if (!threadNameList.contains(cacheKey)) {  
126 - threadNameList.add(cacheKey);  
127 - CheckForAllRecordsThread chk = new CheckForAllRecordsThread(cacheKey, recordInfo);  
128 - chk.setName(cacheKey);  
129 - chk.setDeferredResultHolder(deferredResultHolder);  
130 - chk.setRedis(redis);  
131 - chk.setLogger(logger);  
132 - chk.start();  
133 - if (logger.isDebugEnabled()) {  
134 - logger.debug("Start Thread " + cacheKey + ".");  
135 - }  
136 - } else {  
137 - if (logger.isDebugEnabled()) {  
138 - logger.debug("Thread " + cacheKey + " already started.");  
139 - } 118 +
  119 + if (recordDataCatch.isComplete(device.getDeviceId(), sn)){
  120 + releaseRequest(device.getDeviceId(), sn);
140 } 121 }
141 } 122 }
142 } catch (SipException e) { 123 } catch (SipException e) {
@@ -154,4 +135,20 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent @@ -154,4 +135,20 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent
154 public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) { 135 public void handForPlatform(RequestEvent evt, ParentPlatform parentPlatform, Element element) {
155 136
156 } 137 }
  138 +
  139 + public void releaseRequest(String deviceId, String sn){
  140 + String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn;
  141 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  142 + wvpResult.setCode(0);
  143 + wvpResult.setMsg("success");
  144 + // 对数据进行排序
  145 + Collections.sort(recordDataCatch.getRecordInfo(deviceId, sn).getRecordList());
  146 + wvpResult.setData(recordDataCatch.getRecordInfo(deviceId, sn));
  147 +
  148 + RequestMessage msg = new RequestMessage();
  149 + msg.setKey(key);
  150 + msg.setData(wvpResult);
  151 + deferredResultHolder.invokeAllResult(msg);
  152 + recordDataCatch.remove(deviceId, sn);
  153 + }
157 } 154 }
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRunner.java
@@ -89,7 +89,7 @@ public class ZLMRunner implements CommandLineRunner { @@ -89,7 +89,7 @@ public class ZLMRunner implements CommandLineRunner {
89 }); 89 });
90 90
91 // 获取zlm信息 91 // 获取zlm信息
92 - logger.info("[zlm接入]等待默认zlm中..."); 92 + logger.info("[zlm] 等待默认zlm中...");
93 93
94 // 获取所有的zlm, 并开启主动连接 94 // 获取所有的zlm, 并开启主动连接
95 List<MediaServerItem> all = mediaServerService.getAllFromDatabase(); 95 List<MediaServerItem> all = mediaServerService.getAllFromDatabase();
src/main/java/com/genersoft/iot/vmp/media/zlm/event/ZLMStatusEventListener.java
@@ -39,8 +39,7 @@ public class ZLMStatusEventListener { @@ -39,8 +39,7 @@ public class ZLMStatusEventListener {
39 @Async 39 @Async
40 @EventListener 40 @EventListener
41 public void onApplicationEvent(ZLMOnlineEvent event) { 41 public void onApplicationEvent(ZLMOnlineEvent event) {
42 -  
43 - logger.info("【ZLM上线】ID:" + event.getMediaServerId()); 42 + logger.info("[ZLM] 上线 ID:" + event.getMediaServerId());
44 streamPushService.zlmServerOnline(event.getMediaServerId()); 43 streamPushService.zlmServerOnline(event.getMediaServerId());
45 streamProxyService.zlmServerOnline(event.getMediaServerId()); 44 streamProxyService.zlmServerOnline(event.getMediaServerId());
46 45
@@ -50,7 +49,7 @@ public class ZLMStatusEventListener { @@ -50,7 +49,7 @@ public class ZLMStatusEventListener {
50 @EventListener 49 @EventListener
51 public void onApplicationEvent(ZLMOfflineEvent event) { 50 public void onApplicationEvent(ZLMOfflineEvent event) {
52 51
53 - logger.info("ZLM离线事件触发,ID:" + event.getMediaServerId()); 52 + logger.info("[ZLM] 离线,ID:" + event.getMediaServerId());
54 // 处理ZLM离线 53 // 处理ZLM离线
55 mediaServerService.zlmServerOffline(event.getMediaServerId()); 54 mediaServerService.zlmServerOffline(event.getMediaServerId());
56 streamProxyService.zlmServerOffline(event.getMediaServerId()); 55 streamProxyService.zlmServerOffline(event.getMediaServerId());
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
@@ -44,7 +44,7 @@ public interface IMediaServerService { @@ -44,7 +44,7 @@ public interface IMediaServerService {
44 44
45 void updateVmServer(List<MediaServerItem> mediaServerItemList); 45 void updateVmServer(List<MediaServerItem> mediaServerItemList);
46 46
47 - SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck); 47 + SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback);
48 48
49 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback); 49 SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, String ssrc, boolean ssrcCheck, boolean isPlayback);
50 50
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
@@ -11,24 +11,18 @@ import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; @@ -11,24 +11,18 @@ import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask;
11 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; 11 import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask;
12 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; 12 import com.genersoft.iot.vmp.gb28181.bean.SyncStatus;
13 import com.genersoft.iot.vmp.service.IMediaServerService; 13 import com.genersoft.iot.vmp.service.IMediaServerService;
14 -import com.genersoft.iot.vmp.service.IMediaService;  
15 import com.genersoft.iot.vmp.storager.IRedisCatchStorage; 14 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
16 import com.genersoft.iot.vmp.storager.dao.DeviceMapper; 15 import com.genersoft.iot.vmp.storager.dao.DeviceMapper;
17 import com.genersoft.iot.vmp.utils.DateUtil; 16 import com.genersoft.iot.vmp.utils.DateUtil;
18 import org.slf4j.Logger; 17 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory; 18 import org.slf4j.LoggerFactory;
20 import org.springframework.beans.factory.annotation.Autowired; 19 import org.springframework.beans.factory.annotation.Autowired;
21 -import org.springframework.beans.factory.annotation.Qualifier;  
22 -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;  
23 import org.springframework.stereotype.Service; 20 import org.springframework.stereotype.Service;
24 import org.springframework.util.StringUtils; 21 import org.springframework.util.StringUtils;
25 22
26 -import javax.sip.DialogState;  
27 -import javax.sip.TimeoutEvent;  
28 -import java.text.ParseException;  
29 -import java.util.Calendar;  
30 -import java.util.Date; 23 +import java.time.Instant;
31 import java.util.List; 24 import java.util.List;
  25 +import java.util.concurrent.TimeUnit;
32 26
33 /** 27 /**
34 * 设备业务(目录订阅) 28 * 设备业务(目录订阅)
@@ -66,7 +60,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -66,7 +60,7 @@ public class DeviceServiceImpl implements IDeviceService {
66 60
67 @Override 61 @Override
68 public void online(Device device) { 62 public void online(Device device) {
69 - logger.info("[设备上线],deviceId:" + device.getDeviceId()); 63 + logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort());
70 Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId()); 64 Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId());
71 Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId()); 65 Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId());
72 66
@@ -101,9 +95,7 @@ public class DeviceServiceImpl implements IDeviceService { @@ -101,9 +95,7 @@ public class DeviceServiceImpl implements IDeviceService {
101 // 刷新过期任务 95 // 刷新过期任务
102 String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId(); 96 String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId();
103 dynamicTask.stop(registerExpireTaskKey); 97 dynamicTask.stop(registerExpireTaskKey);
104 - dynamicTask.startDelay(registerExpireTaskKey, ()->{  
105 - offline(device.getDeviceId());  
106 - }, device.getExpires() * 1000); 98 + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId()), device.getExpires() * 1000);
107 } 99 }
108 100
109 @Override 101 @Override
@@ -217,18 +209,9 @@ public class DeviceServiceImpl implements IDeviceService { @@ -217,18 +209,9 @@ public class DeviceServiceImpl implements IDeviceService {
217 209
218 @Override 210 @Override
219 public boolean expire(Device device) { 211 public boolean expire(Device device) {
220 - Date registerTimeDate;  
221 - try {  
222 - registerTimeDate = DateUtil.format.parse(device.getRegisterTime());  
223 - } catch (ParseException e) {  
224 - logger.error("设备时间格式化失败:{}->{} ", device.getDeviceId(), device.getRegisterTime() );  
225 - return false;  
226 - }  
227 - int expires = device.getExpires();  
228 - Calendar calendarForExpire = Calendar.getInstance();  
229 - calendarForExpire.setTime(registerTimeDate);  
230 - calendarForExpire.set(Calendar.SECOND, calendarForExpire.get(Calendar.SECOND) + expires);  
231 - return calendarForExpire.before(DateUtil.getNow()); 212 + Instant registerTimeDate = Instant.from(DateUtil.formatter.parse(device.getRegisterTime()));
  213 + Instant expireInstant = registerTimeDate.plusMillis(TimeUnit.SECONDS.toMillis(device.getExpires()));
  214 + return expireInstant.isBefore(Instant.now());
232 } 215 }
233 216
234 @Override 217 @Override
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
@@ -95,7 +95,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -95,7 +95,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
95 */ 95 */
96 @Override 96 @Override
97 public void updateVmServer(List<MediaServerItem> mediaServerItemList) { 97 public void updateVmServer(List<MediaServerItem> mediaServerItemList) {
98 - logger.info("[缓存初始化] Media Server "); 98 + logger.info("[zlm] 缓存初始化 ");
99 for (MediaServerItem mediaServerItem : mediaServerItemList) { 99 for (MediaServerItem mediaServerItem : mediaServerItemList) {
100 if (StringUtils.isEmpty(mediaServerItem.getId())) { 100 if (StringUtils.isEmpty(mediaServerItem.getId())) {
101 continue; 101 continue;
@@ -116,8 +116,8 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -116,8 +116,8 @@ public class MediaServerServiceImpl implements IMediaServerService {
116 } 116 }
117 117
118 @Override 118 @Override
119 - public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck) {  
120 - return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,false); 119 + public SSRCInfo openRTPServer(MediaServerItem mediaServerItem, String streamId, boolean ssrcCheck, boolean isPlayback) {
  120 + return openRTPServer(mediaServerItem, streamId, null, ssrcCheck,isPlayback);
121 } 121 }
122 122
123 @Override 123 @Override
@@ -352,7 +352,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -352,7 +352,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
352 */ 352 */
353 @Override 353 @Override
354 public void zlmServerOnline(ZLMServerConfig zlmServerConfig) { 354 public void zlmServerOnline(ZLMServerConfig zlmServerConfig) {
355 - logger.info("[ ZLM:{} ]-[ {}:{} ]正在连接", 355 + logger.info("[ZLM] 正在连接 : {} -> {}:{}",
356 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); 356 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
357 357
358 MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()); 358 MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId());
@@ -405,7 +405,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -405,7 +405,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
405 setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); 405 setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable()));
406 } 406 }
407 publisher.zlmOnlineEventPublish(serverItem.getId()); 407 publisher.zlmOnlineEventPublish(serverItem.getId());
408 - logger.info("[ ZLM:{} ]-[ {}:{} ]连接成功", 408 + logger.info("[ZLM] 连接成功 {} - {}:{} ",
409 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); 409 zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort());
410 } 410 }
411 411
@@ -483,7 +483,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -483,7 +483,7 @@ public class MediaServerServiceImpl implements IMediaServerService {
483 */ 483 */
484 @Override 484 @Override
485 public void setZLMConfig(MediaServerItem mediaServerItem, boolean restart) { 485 public void setZLMConfig(MediaServerItem mediaServerItem, boolean restart) {
486 - logger.info("[ ZLM:{} ]-[ {}:{} ]正在设置zlm", 486 + logger.info("[ZLM] 正在设置 :{} -> {}:{}",
487 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); 487 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
488 String protocol = sslEnabled ? "https" : "http"; 488 String protocol = sslEnabled ? "https" : "http";
489 String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); 489 String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort);
@@ -527,17 +527,17 @@ public class MediaServerServiceImpl implements IMediaServerService { @@ -527,17 +527,17 @@ public class MediaServerServiceImpl implements IMediaServerService {
527 527
528 if (responseJSON != null && responseJSON.getInteger("code") == 0) { 528 if (responseJSON != null && responseJSON.getInteger("code") == 0) {
529 if (restart) { 529 if (restart) {
530 - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm成功, 开始重启以保证配置生效", 530 + logger.info("[ZLM] 设置成功,开始重启以保证配置生效 {} -> {}:{}",
531 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); 531 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
532 zlmresTfulUtils.restartServer(mediaServerItem); 532 zlmresTfulUtils.restartServer(mediaServerItem);
533 }else { 533 }else {
534 - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm成功", 534 + logger.info("[ZLM] 设置成功 {} -> {}:{}",
535 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); 535 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
536 } 536 }
537 537
538 538
539 }else { 539 }else {
540 - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm失败", 540 + logger.info("[ZLM] 设置zlm失败 {} -> {}:{}",
541 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); 541 mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort());
542 } 542 }
543 543
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
@@ -193,7 +193,7 @@ public class PlayServiceImpl implements IPlayService { @@ -193,7 +193,7 @@ public class PlayServiceImpl implements IPlayService {
193 if (mediaServerItem.isRtpEnable()) { 193 if (mediaServerItem.isRtpEnable()) {
194 streamId = String.format("%s_%s", device.getDeviceId(), channelId); 194 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
195 } 195 }
196 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck()); 196 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
197 play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{ 197 play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{
198 if (hookEvent != null) { 198 if (hookEvent != null) {
199 hookEvent.response(mediaServerItem, response); 199 hookEvent.response(mediaServerItem, response);
@@ -237,7 +237,7 @@ public class PlayServiceImpl implements IPlayService { @@ -237,7 +237,7 @@ public class PlayServiceImpl implements IPlayService {
237 streamId = String.format("%s_%s", device.getDeviceId(), channelId); 237 streamId = String.format("%s_%s", device.getDeviceId(), channelId);
238 } 238 }
239 if (ssrcInfo == null) { 239 if (ssrcInfo == null) {
240 - ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck()); 240 + ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, streamId, device.isSsrcCheck(), false);
241 } 241 }
242 242
243 // 超时处理 243 // 超时处理
@@ -360,7 +360,7 @@ public class PlayServiceImpl implements IPlayService { @@ -360,7 +360,7 @@ public class PlayServiceImpl implements IPlayService {
360 return null; 360 return null;
361 } 361 }
362 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 362 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
363 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); 363 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true, true);
364 364
365 return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); 365 return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback);
366 } 366 }
@@ -447,7 +447,7 @@ public class PlayServiceImpl implements IPlayService { @@ -447,7 +447,7 @@ public class PlayServiceImpl implements IPlayService {
447 return null; 447 return null;
448 } 448 }
449 MediaServerItem newMediaServerItem = getNewMediaServerItem(device); 449 MediaServerItem newMediaServerItem = getNewMediaServerItem(device);
450 - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true); 450 + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(newMediaServerItem, null, true, true);
451 451
452 return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed,infoCallBack, hookCallBack); 452 return download(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, downloadSpeed,infoCallBack, hookCallBack);
453 } 453 }
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
1 package com.genersoft.iot.vmp.utils; 1 package com.genersoft.iot.vmp.utils;
2 2
3 -import java.text.ParseException; 3 +
4 import java.text.SimpleDateFormat; 4 import java.text.SimpleDateFormat;
5 -import java.util.Date; 5 +import java.time.Instant;
  6 +import java.time.LocalDate;
  7 +import java.time.LocalDateTime;
  8 +import java.time.ZoneId;
  9 +import java.time.format.DateTimeFormatter;
  10 +import java.time.format.DateTimeParseException;
  11 +import java.time.temporal.TemporalAccessor;
  12 +
6 import java.util.Locale; 13 import java.util.Locale;
7 14
8 /** 15 /**
9 * 全局时间工具类 16 * 全局时间工具类
10 - * @author swwheihei 17 + * @author lin
11 */ 18 */
12 public class DateUtil { 19 public class DateUtil {
13 20
14 private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss"; 21 private static final String yyyy_MM_dd_T_HH_mm_ss_SSSXXX = "yyyy-MM-dd'T'HH:mm:ss";
15 - private static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss"; 22 + public static final String yyyy_MM_dd_HH_mm_ss = "yyyy-MM-dd HH:mm:ss";
16 23
17 public static final SimpleDateFormat formatISO8601 = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); 24 public static final SimpleDateFormat formatISO8601 = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault());
18 public static final SimpleDateFormat format = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()); 25 public static final SimpleDateFormat format = new SimpleDateFormat(yyyy_MM_dd_HH_mm_ss, Locale.getDefault());
19 26
20 - public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { 27 + public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()).withZone(ZoneId.systemDefault());
  28 + public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(yyyy_MM_dd_HH_mm_ss, Locale.getDefault()).withZone(ZoneId.systemDefault());
21 29
22 - try {  
23 - return formatISO8601.format(format.parse(formatTime));  
24 - } catch (ParseException e) {  
25 - e.printStackTrace();  
26 - }  
27 - return ""; 30 + public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) {
  31 + return formatterISO8601.format(formatter.parse(formatTime));
28 } 32 }
29 33
30 public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) { 34 public static String ISO8601Toyyyy_MM_dd_HH_mm_ss(String formatTime) {
  35 + return formatter.format(formatterISO8601.parse(formatTime));
31 36
32 - try {  
33 - return format.format(formatISO8601.parse(formatTime));  
34 - } catch (ParseException e) {  
35 - e.printStackTrace();  
36 - }  
37 - return "";  
38 } 37 }
39 38
40 public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) { 39 public static long yyyy_MM_dd_HH_mm_ssToTimestamp(String formatTime) {
41 - //设置要读取的时间字符串格式  
42 - Date date;  
43 - try {  
44 - date = format.parse(formatTime);  
45 - Long timestamp=date.getTime()/1000;  
46 - //转换为Date类  
47 - return timestamp;  
48 - } catch (ParseException e) {  
49 - e.printStackTrace();  
50 - }  
51 - return 0; 40 + TemporalAccessor temporalAccessor = formatter.parse(formatTime);
  41 + Instant instant = Instant.from(temporalAccessor);
  42 + return instant.getEpochSecond();
52 } 43 }
53 44
54 public static String getNow() { 45 public static String getNow() {
55 - return format.format(System.currentTimeMillis()); 46 + LocalDateTime nowDateTime = LocalDateTime.now();
  47 + return formatter.format(nowDateTime);
  48 + }
  49 +
  50 + public static boolean verification(String timeStr, DateTimeFormatter dateTimeFormatter) {
  51 + try {
  52 + LocalDate.parse(timeStr, dateTimeFormatter);
  53 + return true;
  54 + }catch (DateTimeParseException exception) {
  55 + return false;
  56 + }
56 } 57 }
57 } 58 }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
@@ -5,6 +5,8 @@ import com.genersoft.iot.vmp.common.StreamInfo; @@ -5,6 +5,8 @@ import com.genersoft.iot.vmp.common.StreamInfo;
5 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; 5 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
6 import com.genersoft.iot.vmp.service.IMediaServerService; 6 import com.genersoft.iot.vmp.service.IMediaServerService;
7 import com.genersoft.iot.vmp.service.IPlayService; 7 import com.genersoft.iot.vmp.service.IPlayService;
  8 +import com.genersoft.iot.vmp.utils.DateUtil;
  9 +import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
8 import io.swagger.annotations.Api; 10 import io.swagger.annotations.Api;
9 import io.swagger.annotations.ApiImplicitParam; 11 import io.swagger.annotations.ApiImplicitParam;
10 import io.swagger.annotations.ApiImplicitParams; 12 import io.swagger.annotations.ApiImplicitParams;
@@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; @@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
27 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; 29 import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander;
28 import com.genersoft.iot.vmp.storager.IVideoManagerStorage; 30 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
29 31
  32 +import java.time.LocalDate;
30 import java.util.UUID; 33 import java.util.UUID;
31 34
32 @Api(tags = "国标录像") 35 @Api(tags = "国标录像")
@@ -60,15 +63,32 @@ public class GBRecordController { @@ -60,15 +63,32 @@ public class GBRecordController {
60 @ApiImplicitParam(name = "endTime", value = "结束时间", dataTypeClass = String.class), 63 @ApiImplicitParam(name = "endTime", value = "结束时间", dataTypeClass = String.class),
61 }) 64 })
62 @GetMapping("/query/{deviceId}/{channelId}") 65 @GetMapping("/query/{deviceId}/{channelId}")
63 - public DeferredResult<ResponseEntity<RecordInfo>> recordinfo(@PathVariable String deviceId,@PathVariable String channelId, String startTime, String endTime){ 66 + public DeferredResult<ResponseEntity<WVPResult<RecordInfo>>> recordinfo(@PathVariable String deviceId, @PathVariable String channelId, String startTime, String endTime){
64 67
65 if (logger.isDebugEnabled()) { 68 if (logger.isDebugEnabled()) {
66 logger.debug(String.format("录像信息查询 API调用,deviceId:%s ,startTime:%s, endTime:%s",deviceId, startTime, endTime)); 69 logger.debug(String.format("录像信息查询 API调用,deviceId:%s ,startTime:%s, endTime:%s",deviceId, startTime, endTime));
67 } 70 }
  71 + DeferredResult<ResponseEntity<WVPResult<RecordInfo>>> result = new DeferredResult<>();
  72 + if (!DateUtil.verification(startTime, DateUtil.formatter)){
  73 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  74 + wvpResult.setCode(-1);
  75 + wvpResult.setMsg("startTime error, format is " + DateUtil.yyyy_MM_dd_HH_mm_ss);
  76 +
  77 + ResponseEntity<WVPResult<RecordInfo>> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK);
  78 + result.setResult(resultResponseEntity);
  79 + return result;
  80 + }
  81 + if (!DateUtil.verification(endTime, DateUtil.formatter)){
  82 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  83 + wvpResult.setCode(-1);
  84 + wvpResult.setMsg("endTime error, format is " + DateUtil.yyyy_MM_dd_HH_mm_ss);
  85 + ResponseEntity<WVPResult<RecordInfo>> resultResponseEntity = new ResponseEntity<>(wvpResult, HttpStatus.OK);
  86 + result.setResult(resultResponseEntity);
  87 + return result;
  88 + }
68 89
69 Device device = storager.queryVideoDevice(deviceId); 90 Device device = storager.queryVideoDevice(deviceId);
70 // 指定超时时间 1分钟30秒 91 // 指定超时时间 1分钟30秒
71 - DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<>(90*1000L);  
72 String uuid = UUID.randomUUID().toString(); 92 String uuid = UUID.randomUUID().toString();
73 int sn = (int)((Math.random()*9+1)*100000); 93 int sn = (int)((Math.random()*9+1)*100000);
74 String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; 94 String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn;
@@ -76,7 +96,10 @@ public class GBRecordController { @@ -76,7 +96,10 @@ public class GBRecordController {
76 msg.setId(uuid); 96 msg.setId(uuid);
77 msg.setKey(key); 97 msg.setKey(key);
78 cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> { 98 cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> {
79 - msg.setData("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg ); 99 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  100 + wvpResult.setCode(-1);
  101 + wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg);
  102 + msg.setData(wvpResult);
80 resultHolder.invokeResult(msg); 103 resultHolder.invokeResult(msg);
81 })); 104 }));
82 105
@@ -84,6 +107,10 @@ public class GBRecordController { @@ -84,6 +107,10 @@ public class GBRecordController {
84 resultHolder.put(key, uuid, result); 107 resultHolder.put(key, uuid, result);
85 result.onTimeout(()->{ 108 result.onTimeout(()->{
86 msg.setData("timeout"); 109 msg.setData("timeout");
  110 + WVPResult<RecordInfo> wvpResult = new WVPResult<>();
  111 + wvpResult.setCode(-1);
  112 + wvpResult.setMsg("timeout");
  113 + msg.setData(wvpResult);
87 resultHolder.invokeResult(msg); 114 resultHolder.invokeResult(msg);
88 }); 115 });
89 return result; 116 return result;
src/main/resources/all-application.yml
@@ -28,7 +28,7 @@ spring: @@ -28,7 +28,7 @@ spring:
28 poolMaxIdle: 500 28 poolMaxIdle: 500
29 # [可选] 最大的等待时间(秒) 29 # [可选] 最大的等待时间(秒)
30 poolMaxWait: 5 30 poolMaxWait: 5
31 - # [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置 31 + # [必选] jdbc数据库配置
32 datasource: 32 datasource:
33 type: com.alibaba.druid.pool.DruidDataSource 33 type: com.alibaba.druid.pool.DruidDataSource
34 driver-class-name: com.mysql.cj.jdbc.Driver 34 driver-class-name: com.mysql.cj.jdbc.Driver
src/main/resources/application-dev.yml
@@ -16,7 +16,6 @@ spring: @@ -16,7 +16,6 @@ spring:
16 password: face2020 16 password: face2020
17 # [可选] 超时时间 17 # [可选] 超时时间
18 timeout: 10000 18 timeout: 10000
19 - # [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置  
20 # mysql数据源 19 # mysql数据源
21 datasource: 20 datasource:
22 type: com.alibaba.druid.pool.DruidDataSource 21 type: com.alibaba.druid.pool.DruidDataSource
src/main/resources/application-docker.yml
@@ -16,7 +16,7 @@ spring: @@ -16,7 +16,7 @@ spring:
16 password: ${REDIS_PWD:root} 16 password: ${REDIS_PWD:root}
17 # [可选] 超时时间 17 # [可选] 超时时间
18 timeout: 10000 18 timeout: 10000
19 - # [可选] jdbc数据库配置, 项目使用sqlite作为数据库,一般不需要配置 19 + # [必选] jdbc数据库配置
20 datasource: 20 datasource:
21 # 使用mysql 打开23-28行注释, 删除29-36行 21 # 使用mysql 打开23-28行注释, 删除29-36行
22 name: wvp 22 name: wvp
web_src/src/components/channelList.vue
@@ -244,7 +244,7 @@ export default { @@ -244,7 +244,7 @@ export default {
244 }); 244 });
245 }, 245 },
246 queryRecords: function (itemData) { 246 queryRecords: function (itemData) {
247 - var format = moment().format("YYYY-M-D"); 247 + var format = moment().format("yyyy-MM-DD");
248 let deviceId = this.deviceId; 248 let deviceId = this.deviceId;
249 let channelId = itemData.channelId; 249 let channelId = itemData.channelId;
250 this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) 250 this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format})
web_src/src/components/dialog/devicePlayer.vue
@@ -453,9 +453,19 @@ export default { @@ -453,9 +453,19 @@ export default {
453 method: 'get', 453 method: 'get',
454 url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + startTime + '&endTime=' + endTime 454 url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + startTime + '&endTime=' + endTime
455 }).then(function (res) { 455 }).then(function (res) {
456 - // 处理时间信息  
457 - that.videoHistory.searchHistoryResult = res.data.recordList;  
458 - that.recordsLoading = false; 456 + console.log(res)
  457 + if(res.data.code === 0) {
  458 + // 处理时间信息
  459 + that.videoHistory.searchHistoryResult = res.data.data.recordList;
  460 + that.recordsLoading = false;
  461 + }else {
  462 + this.$message({
  463 + showClose: true,
  464 + message: res.data.msg,
  465 + type: "error",
  466 + });
  467 + }
  468 +
459 }).catch(function (e) { 469 }).catch(function (e) {
460 console.log(e.message); 470 console.log(e.message);
461 // that.videoHistory.searchHistoryResult = falsificationData.recordData; 471 // that.videoHistory.searchHistoryResult = falsificationData.recordData;
@@ -671,7 +681,11 @@ export default { @@ -671,7 +681,11 @@ export default {
671 this.$axios({ 681 this.$axios({
672 method: 'get', 682 method: 'get',
673 url: `/api/playback/seek/${this.streamId }/` + Math.floor(this.seekTime * val / 100000) 683 url: `/api/playback/seek/${this.streamId }/` + Math.floor(this.seekTime * val / 100000)
674 - }).then(function (res) {}); 684 + }).then( (res)=> {
  685 + setTimeout(()=>{
  686 + this.$refs.videoPlayer.play(this.videoUrl)
  687 + }, 600)
  688 + });
675 } 689 }
676 690
677 } 691 }
web_src/src/components/dialog/recordDownload.vue
@@ -172,6 +172,7 @@ export default { @@ -172,6 +172,7 @@ export default {
172 isEnd: true, 172 isEnd: true,
173 } 173 }
174 }).then((res) => { 174 }).then((res) => {
  175 + console.log(res)
175 if (res.data.code == 0) { 176 if (res.data.code == 0) {
176 this.percentage = parseFloat(res.data.data.percentage)*100 177 this.percentage = parseFloat(res.data.data.percentage)*100
177 if (res.data.data[0].percentage === '1') { 178 if (res.data.data[0].percentage === '1') {