Commit e6790d88fc5b1ac33d239c0d90ce6cdea666b821
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 | 106 | - [X] 添加RTMP视频 |
| 107 | 107 | - [X] 云端录像(需要部署单独服务配合使用) |
| 108 | 108 | - [X] 多流媒体节点,自动选择负载最低的节点使用。 |
| 109 | -- [X] 支持使用mysql作为数据库,默认sqlite3,开箱即用。 | |
| 110 | 109 | - [X] WEB端支持播放H264与H265,音频支持G.711A/G.711U/AAC,覆盖国标常用编码格式。 |
| 111 | 110 | |
| 112 | 111 | [//]: # (# docker快速体验) | ... | ... |
pom.xml
| ... | ... | @@ -101,13 +101,6 @@ |
| 101 | 101 | <version>8.0.22</version> |
| 102 | 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 | 104 | <!--Mybatis分页插件 --> |
| 112 | 105 | <dependency> |
| 113 | 106 | <groupId>com.github.pagehelper</groupId> | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/DynamicTask.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | 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 | 4 | import org.slf4j.Logger; |
| 6 | 5 | import org.slf4j.LoggerFactory; |
| 7 | 6 | import org.springframework.beans.factory.annotation.Autowired; |
| ... | ... | @@ -9,25 +8,27 @@ import org.springframework.context.annotation.Bean; |
| 9 | 8 | import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; |
| 10 | 9 | import org.springframework.stereotype.Component; |
| 11 | 10 | |
| 12 | -import java.util.Date; | |
| 11 | +import java.time.Instant; | |
| 13 | 12 | import java.util.Map; |
| 14 | 13 | import java.util.Set; |
| 15 | 14 | import java.util.concurrent.ConcurrentHashMap; |
| 16 | 15 | import java.util.concurrent.ScheduledFuture; |
| 16 | +import java.util.concurrent.TimeUnit; | |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | 19 | * 动态定时任务 |
| 20 | + * @author lin | |
| 20 | 21 | */ |
| 21 | 22 | @Component |
| 22 | 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 | 27 | @Autowired |
| 27 | 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 | 33 | @Bean |
| 33 | 34 | public ThreadPoolTaskScheduler threadPoolTaskScheduler() { |
| ... | ... | @@ -47,7 +48,7 @@ public class DynamicTask { |
| 47 | 48 | * @return |
| 48 | 49 | */ |
| 49 | 50 | public void startCron(String key, Runnable task, int cycleForCatalog) { |
| 50 | - ScheduledFuture future = futureMap.get(key); | |
| 51 | + ScheduledFuture<?> future = futureMap.get(key); | |
| 51 | 52 | if (future != null) { |
| 52 | 53 | if (future.isCancelled()) { |
| 53 | 54 | logger.debug("任务【{}】已存在但是关闭状态!!!", key); |
| ... | ... | @@ -76,7 +77,9 @@ public class DynamicTask { |
| 76 | 77 | */ |
| 77 | 78 | public void startDelay(String key, Runnable task, int delay) { |
| 78 | 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 | 84 | ScheduledFuture future = futureMap.get(key); |
| 82 | 85 | if (future != null) { |
| ... | ... | @@ -88,7 +91,7 @@ public class DynamicTask { |
| 88 | 91 | } |
| 89 | 92 | } |
| 90 | 93 | // scheduleWithFixedDelay 必须等待上一个任务结束才开始计时period, cycleForCatalog表示执行的间隔 |
| 91 | - future = threadPoolTaskScheduler.schedule(task, starTime); | |
| 94 | + future = threadPoolTaskScheduler.schedule(task, startInstant); | |
| 92 | 95 | if (future != null){ |
| 93 | 96 | futureMap.put(key, future); |
| 94 | 97 | runnableMap.put(key, task); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java
| ... | ... | @@ -81,11 +81,11 @@ public class SipLayer{ |
| 81 | 81 | tcpSipProvider.setDialogErrorsAutomaticallyHandled(); |
| 82 | 82 | tcpSipProvider.addSipListener(sipProcessorObserver); |
| 83 | 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 | 85 | } catch (TransportNotSupportedException e) { |
| 86 | 86 | e.printStackTrace(); |
| 87 | 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 | 89 | , sipConfig.getMonitorIp(), sipConfig.getPort()); |
| 90 | 90 | } catch (TooManyListenersException e) { |
| 91 | 91 | e.printStackTrace(); |
| ... | ... | @@ -108,14 +108,14 @@ public class SipLayer{ |
| 108 | 108 | } catch (TransportNotSupportedException e) { |
| 109 | 109 | e.printStackTrace(); |
| 110 | 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 | 112 | , sipConfig.getMonitorIp(), sipConfig.getPort()); |
| 113 | 113 | } catch (TooManyListenersException e) { |
| 114 | 114 | e.printStackTrace(); |
| 115 | 115 | } catch (ObjectInUseException e) { |
| 116 | 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 | 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 | 27 | |
| 28 | 28 | import java.security.MessageDigest; |
| 29 | 29 | import java.security.NoSuchAlgorithmException; |
| 30 | -import java.text.DecimalFormat; | |
| 31 | -import java.util.Date; | |
| 30 | +import java.time.Instant; | |
| 32 | 31 | import java.util.Random; |
| 33 | 32 | |
| 34 | 33 | import javax.sip.address.URI; |
| ... | ... | @@ -90,17 +89,12 @@ public class DigestServerAuthenticationHelper { |
| 90 | 89 | * @return a generated nonce. |
| 91 | 90 | */ |
| 92 | 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 | 93 | Random rand = new Random(); |
| 97 | 94 | long pad = rand.nextLong(); |
| 98 | - // String nonceString = (new Long(time)).toString() | |
| 99 | - // + (new Long(pad)).toString(); | |
| 100 | 95 | String nonceString = Long.valueOf(time).toString() |
| 101 | 96 | + Long.valueOf(pad).toString(); |
| 102 | 97 | byte mdbytes[] = messageDigest.digest(nonceString.getBytes()); |
| 103 | - // Convert the mdbytes array into a hex string. | |
| 104 | 98 | return toHexString(mdbytes); |
| 105 | 99 | } |
| 106 | 100 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/CatalogData.java
| 1 | 1 | package com.genersoft.iot.vmp.gb28181.bean; |
| 2 | 2 | |
| 3 | -import java.util.Date; | |
| 3 | +import java.time.Instant; | |
| 4 | 4 | import java.util.List; |
| 5 | 5 | |
| 6 | 6 | public class CatalogData { |
| 7 | 7 | private int sn; // 命令序列号 |
| 8 | 8 | private int total; |
| 9 | 9 | private List<DeviceChannel> channelList; |
| 10 | - private Date lastTime; | |
| 10 | + private Instant lastTime; | |
| 11 | 11 | private Device device; |
| 12 | 12 | private String errorMsg; |
| 13 | 13 | |
| ... | ... | @@ -41,11 +41,11 @@ public class CatalogData { |
| 41 | 41 | this.channelList = channelList; |
| 42 | 42 | } |
| 43 | 43 | |
| 44 | - public Date getLastTime() { | |
| 44 | + public Instant getLastTime() { | |
| 45 | 45 | return lastTime; |
| 46 | 46 | } |
| 47 | 47 | |
| 48 | - public void setLastTime(Date lastTime) { | |
| 48 | + public void setLastTime(Instant lastTime) { | |
| 49 | 49 | this.lastTime = lastTime; |
| 50 | 50 | } |
| 51 | 51 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/bean/RecordInfo.java
| 1 | 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 | 4 | import java.util.List; |
| 7 | 5 | |
| 8 | 6 | /** |
| ... | ... | @@ -21,6 +19,8 @@ public class RecordInfo { |
| 21 | 19 | private String name; |
| 22 | 20 | |
| 23 | 21 | private int sumNum; |
| 22 | + | |
| 23 | + private Instant lastTime; | |
| 24 | 24 | |
| 25 | 25 | private List<RecordItem> recordList; |
| 26 | 26 | |
| ... | ... | @@ -71,4 +71,12 @@ public class RecordInfo { |
| 71 | 71 | public void setSn(String sn) { |
| 72 | 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 | 5 | import org.jetbrains.annotations.NotNull; |
| 6 | 6 | |
| 7 | 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 | 12 | * @description:设备录像bean |
| ... | ... | @@ -116,17 +117,17 @@ public class RecordItem implements Comparable<RecordItem>{ |
| 116 | 117 | |
| 117 | 118 | @Override |
| 118 | 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 | 66 | dynamicTask.stop(taskOverdueKey); |
| 67 | 67 | // 添加任务处理订阅过期 |
| 68 | 68 | dynamicTask.startDelay(taskOverdueKey, () -> { |
| 69 | - System.out.println("订阅过期"); | |
| 70 | 69 | removeMobilePositionSubscribe(subscribeInfo.getId()); |
| 71 | 70 | }, |
| 72 | 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 | 9 | import javax.sip.*; |
| 10 | 10 | import javax.sip.header.CallIdHeader; |
| 11 | 11 | import javax.sip.message.Response; |
| 12 | -import java.util.Calendar; | |
| 13 | -import java.util.Date; | |
| 12 | +import java.time.Instant; | |
| 14 | 13 | import java.util.Map; |
| 15 | 14 | import java.util.concurrent.ConcurrentHashMap; |
| 15 | +import java.util.concurrent.TimeUnit; | |
| 16 | 16 | |
| 17 | +/** | |
| 18 | + * @author lin | |
| 19 | + */ | |
| 17 | 20 | @Component |
| 18 | 21 | public class SipSubscribe { |
| 19 | 22 | |
| ... | ... | @@ -23,28 +26,25 @@ public class SipSubscribe { |
| 23 | 26 | |
| 24 | 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 | 32 | // @Scheduled(cron="*/5 * * * * ?") //每五秒执行一次 |
| 30 | -// @Scheduled(fixedRate= 100 * 60 * 60 ) | |
| 33 | + // @Scheduled(fixedRate= 100 * 60 * 60 ) | |
| 31 | 34 | @Scheduled(cron="0 0/5 * * * ?") //每5分钟执行一次 |
| 32 | 35 | public void execute(){ |
| 33 | 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 | 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 | 42 | okSubscribes.remove(key); |
| 42 | 43 | okTimeSubscribes.remove(key); |
| 43 | 44 | } |
| 44 | 45 | } |
| 45 | 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 | 48 | errorSubscribes.remove(key); |
| 49 | 49 | errorTimeSubscribes.remove(key); |
| 50 | 50 | } |
| ... | ... | @@ -117,12 +117,12 @@ public class SipSubscribe { |
| 117 | 117 | |
| 118 | 118 | public void addErrorSubscribe(String key, SipSubscribe.Event event) { |
| 119 | 119 | errorSubscribes.put(key, event); |
| 120 | - errorTimeSubscribes.put(key, new Date()); | |
| 120 | + errorTimeSubscribes.put(key, Instant.now()); | |
| 121 | 121 | } |
| 122 | 122 | |
| 123 | 123 | public void addOkSubscribe(String key, SipSubscribe.Event event) { |
| 124 | 124 | okSubscribes.put(key, event); |
| 125 | - okTimeSubscribes.put(key, new Date()); | |
| 125 | + okTimeSubscribes.put(key, Instant.now()); | |
| 126 | 126 | } |
| 127 | 127 | |
| 128 | 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 | 4 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 5 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 6 | 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 | 7 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 10 | -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | |
| 11 | 8 | import org.springframework.beans.factory.annotation.Autowired; |
| 12 | 9 | import org.springframework.scheduling.annotation.Scheduled; |
| 13 | 10 | import org.springframework.stereotype.Component; |
| 14 | 11 | |
| 12 | +import java.time.Instant; | |
| 15 | 13 | import java.util.*; |
| 16 | 14 | import java.util.concurrent.ConcurrentHashMap; |
| 15 | +import java.util.concurrent.TimeUnit; | |
| 17 | 16 | |
| 18 | 17 | @Component |
| 19 | 18 | public class CatalogDataCatch { |
| ... | ... | @@ -21,9 +20,6 @@ public class CatalogDataCatch { |
| 21 | 20 | public static Map<String, CatalogData> data = new ConcurrentHashMap<>(); |
| 22 | 21 | |
| 23 | 22 | @Autowired |
| 24 | - private DeferredResultHolder deferredResultHolder; | |
| 25 | - | |
| 26 | - @Autowired | |
| 27 | 23 | private IVideoManagerStorage storager; |
| 28 | 24 | |
| 29 | 25 | public void addReady(Device device, int sn ) { |
| ... | ... | @@ -34,7 +30,7 @@ public class CatalogDataCatch { |
| 34 | 30 | catalogData.setDevice(device); |
| 35 | 31 | catalogData.setSn(sn); |
| 36 | 32 | catalogData.setStatus(CatalogData.CatalogDataStatus.ready); |
| 37 | - catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 33 | + catalogData.setLastTime(Instant.now()); | |
| 38 | 34 | data.put(device.getDeviceId(), catalogData); |
| 39 | 35 | } |
| 40 | 36 | } |
| ... | ... | @@ -48,7 +44,7 @@ public class CatalogDataCatch { |
| 48 | 44 | catalogData.setDevice(device); |
| 49 | 45 | catalogData.setChannelList(Collections.synchronizedList(new ArrayList<>())); |
| 50 | 46 | catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); |
| 51 | - catalogData.setLastTime(new Date(System.currentTimeMillis())); | |
| 47 | + catalogData.setLastTime(Instant.now()); | |
| 52 | 48 | data.put(deviceId, catalogData); |
| 53 | 49 | }else { |
| 54 | 50 | // 同一个设备的通道同步请求只考虑一个,其他的直接忽略 |
| ... | ... | @@ -59,7 +55,7 @@ public class CatalogDataCatch { |
| 59 | 55 | catalogData.setDevice(device); |
| 60 | 56 | catalogData.setStatus(CatalogData.CatalogDataStatus.runIng); |
| 61 | 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 | 98 | @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时 |
| 103 | 99 | private void timerTask(){ |
| 104 | 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 | 105 | for (String deviceId : keys) { |
| 113 | 106 | CatalogData catalogData = data.get(deviceId); |
| 114 | - if ( catalogData.getLastTime().before(calendarBefore5S.getTime())) { // 超过五秒收不到消息任务超时, 只更新这一部分数据 | |
| 107 | + if ( catalogData.getLastTime().isBefore(instantBefore5S)) { // 超过五秒收不到消息任务超时, 只更新这一部分数据 | |
| 115 | 108 | if (catalogData.getStatus().equals(CatalogData.CatalogDataStatus.runIng)) { |
| 116 | 109 | storager.resetChannels(catalogData.getDevice().getDeviceId(), catalogData.getChannelList()); |
| 117 | 110 | if (catalogData.getTotal() != catalogData.getChannelList().size()) { |
| ... | ... | @@ -124,7 +117,7 @@ public class CatalogDataCatch { |
| 124 | 117 | } |
| 125 | 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 | 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 | 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 | 81 | if (ssrcTransaction == null) { |
| 82 | 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 | 370 | // |
| 371 | 371 | StringBuffer content = new StringBuffer(200); |
| 372 | 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 | 374 | content.append("s=Play\r\n"); |
| 375 | 375 | content.append("c=IN IP4 "+ mediaServerItem.getSdpIp() +"\r\n"); |
| 376 | 376 | content.append("t=0 0\r\n"); |
| ... | ... | @@ -389,8 +389,7 @@ public class SIPCommander implements ISIPCommander { |
| 389 | 389 | content.append("a=rtpmap:126 H264/90000\r\n"); |
| 390 | 390 | content.append("a=rtpmap:125 H264S/90000\r\n"); |
| 391 | 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 | 393 | content.append("a=rtpmap:98 H264/90000\r\n"); |
| 395 | 394 | content.append("a=rtpmap:97 MPEG4/90000\r\n"); |
| 396 | 395 | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 |
| ... | ... | @@ -402,16 +401,17 @@ public class SIPCommander implements ISIPCommander { |
| 402 | 401 | } |
| 403 | 402 | }else { |
| 404 | 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 | 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 | 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 | 410 | content.append("a=recvonly\r\n"); |
| 412 | 411 | content.append("a=rtpmap:96 PS/90000\r\n"); |
| 413 | 412 | content.append("a=rtpmap:98 H264/90000\r\n"); |
| 414 | 413 | content.append("a=rtpmap:97 MPEG4/90000\r\n"); |
| 414 | + content.append("a=rtpmap:99 H265/90000\r\n"); | |
| 415 | 415 | if ("TCP-PASSIVE".equals(streamMode)) { // tcp被动模式 |
| 416 | 416 | content.append("a=setup:passive\r\n"); |
| 417 | 417 | content.append("a=connection:new\r\n"); |
| ... | ... | @@ -467,7 +467,7 @@ public class SIPCommander implements ISIPCommander { |
| 467 | 467 | |
| 468 | 468 | StringBuffer content = new StringBuffer(200); |
| 469 | 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 | 471 | content.append("s=Playback\r\n"); |
| 472 | 472 | content.append("u="+channelId+":0\r\n"); |
| 473 | 473 | content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); |
| ... | ... | @@ -490,8 +490,7 @@ public class SIPCommander implements ISIPCommander { |
| 490 | 490 | content.append("a=rtpmap:126 H264/90000\r\n"); |
| 491 | 491 | content.append("a=rtpmap:125 H264S/90000\r\n"); |
| 492 | 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 | 494 | content.append("a=rtpmap:98 H264/90000\r\n"); |
| 496 | 495 | content.append("a=rtpmap:97 MPEG4/90000\r\n"); |
| 497 | 496 | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 |
| ... | ... | @@ -503,16 +502,17 @@ public class SIPCommander implements ISIPCommander { |
| 503 | 502 | } |
| 504 | 503 | }else { |
| 505 | 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 | 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 | 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 | 511 | content.append("a=recvonly\r\n"); |
| 513 | 512 | content.append("a=rtpmap:96 PS/90000\r\n"); |
| 514 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 515 | 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 | 516 | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 |
| 517 | 517 | content.append("a=setup:passive\r\n"); |
| 518 | 518 | content.append("a=connection:new\r\n"); |
| ... | ... | @@ -577,7 +577,7 @@ public class SIPCommander implements ISIPCommander { |
| 577 | 577 | |
| 578 | 578 | StringBuffer content = new StringBuffer(200); |
| 579 | 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 | 581 | content.append("s=Download\r\n"); |
| 582 | 582 | content.append("u="+channelId+":0\r\n"); |
| 583 | 583 | content.append("c=IN IP4 "+mediaServerItem.getSdpIp()+"\r\n"); |
| ... | ... | @@ -613,16 +613,17 @@ public class SIPCommander implements ISIPCommander { |
| 613 | 613 | } |
| 614 | 614 | }else { |
| 615 | 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 | 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 | 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 | 622 | content.append("a=recvonly\r\n"); |
| 623 | 623 | content.append("a=rtpmap:96 PS/90000\r\n"); |
| 624 | - content.append("a=rtpmap:98 H264/90000\r\n"); | |
| 625 | 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 | 627 | if("TCP-PASSIVE".equals(streamMode)){ // tcp被动模式 |
| 627 | 628 | content.append("a=setup:passive\r\n"); |
| 628 | 629 | content.append("a=connection:new\r\n"); |
| ... | ... | @@ -651,6 +652,17 @@ public class SIPCommander implements ISIPCommander { |
| 651 | 652 | (MediaServerItem mediaServerItemInUse, JSONObject json)->{ |
| 652 | 653 | hookEvent.call(new InviteStreamInfo(mediaServerItem, json, callIdHeader.getCallId(), "rtp", ssrcInfo.getStream())); |
| 653 | 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 | 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 | 695 | @Override |
| 684 | 696 | public void streamByeCmd(String deviceId, String channelId, String stream, String callId, SipSubscribe.Event okEvent) { |
| 685 | 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 | 702 | logger.warn("[ {} -> {}]停止视频流的时候发现事务已丢失", deviceId, channelId); |
| 691 | 703 | SipSubscribe.EventResult<Object> eventResult = new SipSubscribe.EventResult<>(); |
| 692 | 704 | if (okEvent != null) { |
| ... | ... | @@ -1663,6 +1675,7 @@ public class SIPCommander implements ISIPCommander { |
| 1663 | 1675 | sipSubscribe.addErrorSubscribe(callIdHeader.getCallId(), (eventResult -> { |
| 1664 | 1676 | errorEvent.response(eventResult); |
| 1665 | 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 | 1683 | sipSubscribe.addOkSubscribe(callIdHeader.getCallId(), eventResult ->{ |
| 1671 | 1684 | okEvent.response(eventResult); |
| 1672 | 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 | 40 | import javax.sip.message.Request; |
| 41 | 41 | import javax.sip.message.Response; |
| 42 | 42 | import java.text.ParseException; |
| 43 | -import java.util.Date; | |
| 43 | +import java.time.Instant; | |
| 44 | 44 | import java.util.Vector; |
| 45 | 45 | |
| 46 | 46 | /** |
| ... | ... | @@ -180,16 +180,16 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 180 | 180 | |
| 181 | 181 | Long startTime = null; |
| 182 | 182 | Long stopTime = null; |
| 183 | - Date start = null; | |
| 184 | - Date end = null; | |
| 183 | + Instant start = null; | |
| 184 | + Instant end = null; | |
| 185 | 185 | if (sdp.getTimeDescriptions(false) != null && sdp.getTimeDescriptions(false).size() > 0) { |
| 186 | 186 | TimeDescriptionImpl timeDescription = (TimeDescriptionImpl)(sdp.getTimeDescriptions(false).get(0)); |
| 187 | 187 | TimeField startTimeFiled = (TimeField)timeDescription.getTime(); |
| 188 | 188 | startTime = startTimeFiled.getStartTime(); |
| 189 | 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 | 195 | Vector mediaDescriptions = sdp.getMediaDescriptions(true); |
| ... | ... | @@ -331,12 +331,12 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 331 | 331 | sendRtpItem.setApp("rtp"); |
| 332 | 332 | if ("Playback".equals(sessionName)) { |
| 333 | 333 | sendRtpItem.setPlayType(InviteStreamType.PLAYBACK); |
| 334 | - SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true); | |
| 334 | + SSRCInfo ssrcInfo = mediaServerService.openRTPServer(mediaServerItem, null, true, true); | |
| 335 | 335 | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| 336 | 336 | // 写入redis, 超时时回复 |
| 337 | 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 | 340 | if (result.getCode() != 0){ |
| 341 | 341 | logger.warn("录像回放失败"); |
| 342 | 342 | if (result.getEvent() != null) { |
| ... | ... | @@ -372,7 +372,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 372 | 372 | if (mediaServerItem.isRtpEnable()) { |
| 373 | 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 | 376 | sendRtpItem.setStreamId(ssrcInfo.getStream()); |
| 377 | 377 | // 写入redis, 超时时回复 |
| 378 | 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 | 81 | try { |
| 82 | 82 | RequestEventExt evtExt = (RequestEventExt) evt; |
| 83 | 83 | String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort(); |
| 84 | - logger.info("[{}] 收到注册请求,开始处理", requestAddress); | |
| 84 | + logger.info("[注册请求] 开始处理: {}", requestAddress); | |
| 85 | 85 | Request request = evt.getRequest(); |
| 86 | 86 | ExpiresHeader expiresHeader = (ExpiresHeader) request.getHeader(Expires.NAME); |
| 87 | 87 | Response response = null; |
| ... | ... | @@ -95,7 +95,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 95 | 95 | |
| 96 | 96 | AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME); |
| 97 | 97 | if (authHead == null) { |
| 98 | - logger.info("[{}] 未携带授权头 回复401", requestAddress); | |
| 98 | + logger.info("[注册请求] 未携带授权头 回复401: {}", requestAddress); | |
| 99 | 99 | response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request); |
| 100 | 100 | new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain()); |
| 101 | 101 | sendResponse(evt, response); |
| ... | ... | @@ -111,7 +111,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 111 | 111 | // 注册失败 |
| 112 | 112 | response = getMessageFactory().createResponse(Response.FORBIDDEN, request); |
| 113 | 113 | response.setReasonPhrase("wrong password"); |
| 114 | - logger.info("[{}] 密码/SIP服务器ID错误, 回复403", requestAddress); | |
| 114 | + logger.info("[注册请求] 密码/SIP服务器ID错误, 回复403: {}", requestAddress); | |
| 115 | 115 | sendResponse(evt, response); |
| 116 | 116 | return; |
| 117 | 117 | } |
| ... | ... | @@ -176,11 +176,11 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 176 | 176 | // 注册成功 |
| 177 | 177 | // 保存到redis |
| 178 | 178 | if (registerFlag) { |
| 179 | - logger.info("[{}] 注册成功! deviceId:" + deviceId, requestAddress); | |
| 179 | + logger.info("[注册成功] deviceId: {}->{}", deviceId, requestAddress); | |
| 180 | 180 | device.setRegisterTime(DateUtil.getNow()); |
| 181 | 181 | deviceService.online(device); |
| 182 | 182 | } else { |
| 183 | - logger.info("[{}] 注销成功! deviceId:" + deviceId, requestAddress); | |
| 183 | + logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress); | |
| 184 | 184 | deviceService.offline(deviceId); |
| 185 | 185 | } |
| 186 | 186 | } catch (SipException | InvalidArgumentException | NoSuchAlgorithmException | ParseException e) { |
| ... | ... | @@ -192,7 +192,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen |
| 192 | 192 | private void sendResponse(RequestEvent evt, Response response) throws InvalidArgumentException, SipException { |
| 193 | 193 | ServerTransaction serverTransaction = getServerTransaction(evt); |
| 194 | 194 | if (serverTransaction == null) { |
| 195 | - logger.warn("回复失败:{}", response); | |
| 195 | + logger.warn("[回复失败]:{}", response); | |
| 196 | 196 | return; |
| 197 | 197 | } |
| 198 | 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 | 24 | import javax.sip.header.ViaHeader; |
| 25 | 25 | import javax.sip.message.Response; |
| 26 | 26 | import java.text.ParseException; |
| 27 | -import java.util.Calendar; | |
| 28 | -import java.util.Date; | |
| 29 | 27 | |
| 30 | 28 | @Component |
| 31 | 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 | 60 | CallIdHeader callIdHeader = (CallIdHeader)evt.getRequest().getHeader(CallIdHeader.NAME); |
| 61 | 61 | String NotifyType =getText(rootElement, "NotifyType"); |
| 62 | 62 | if (NotifyType.equals("121")){ |
| 63 | - logger.info("媒体播放完毕,通知关流"); | |
| 63 | + logger.info("[录像流]推送完毕,收到关流通知"); | |
| 64 | 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 | 66 | StreamInfo streamInfo = redisCatchStorage.queryDownload(device.getDeviceId(), channelId, null, callIdHeader.getCallId()); |
| 68 | 67 | // 设置进度100% |
| 69 | 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 | 5 | import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; |
| 6 | 6 | import com.genersoft.iot.vmp.gb28181.bean.RecordItem; |
| 7 | 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 | 9 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 10 | 10 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 11 | 11 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; |
| 13 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; |
| 14 | 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 | 16 | import org.dom4j.DocumentException; |
| 17 | 17 | import org.dom4j.Element; |
| 18 | 18 | import org.slf4j.Logger; |
| ... | ... | @@ -20,19 +20,20 @@ import org.slf4j.LoggerFactory; |
| 20 | 20 | import org.springframework.beans.factory.InitializingBean; |
| 21 | 21 | import org.springframework.beans.factory.annotation.Autowired; |
| 22 | 22 | import org.springframework.stereotype.Component; |
| 23 | +import org.springframework.util.StringUtils; | |
| 23 | 24 | |
| 24 | 25 | import javax.sip.InvalidArgumentException; |
| 25 | 26 | import javax.sip.RequestEvent; |
| 26 | 27 | import javax.sip.SipException; |
| 27 | 28 | import javax.sip.message.Response; |
| 28 | 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 | 32 | import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; |
| 35 | 33 | |
| 34 | +/** | |
| 35 | + * @author lin | |
| 36 | + */ | |
| 36 | 37 | @Component |
| 37 | 38 | public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { |
| 38 | 39 | |
| ... | ... | @@ -45,11 +46,13 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 45 | 46 | private ResponseMessageHandler responseMessageHandler; |
| 46 | 47 | |
| 47 | 48 | @Autowired |
| 48 | - private RedisUtil redis; | |
| 49 | + private RecordDataCatch recordDataCatch; | |
| 49 | 50 | |
| 50 | 51 | @Autowired |
| 51 | 52 | private DeferredResultHolder deferredResultHolder; |
| 52 | 53 | |
| 54 | + | |
| 55 | + | |
| 53 | 56 | @Autowired |
| 54 | 57 | private EventPublisher eventPublisher; |
| 55 | 58 | |
| ... | ... | @@ -66,32 +69,22 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 66 | 69 | responseAck(evt, Response.OK); |
| 67 | 70 | |
| 68 | 71 | rootElement = getRootElement(evt, device.getCharset()); |
| 69 | - String uuid = UUID.randomUUID().toString().replace("-", ""); | |
| 70 | - RecordInfo recordInfo = new RecordInfo(); | |
| 71 | 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 | 79 | Element recordListElement = rootElement.element("RecordList"); |
| 82 | - if (recordListElement == null || recordInfo.getSumNum() == 0) { | |
| 80 | + if (recordListElement == null || sumNum == 0) { | |
| 83 | 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 | 84 | } else { |
| 90 | 85 | Iterator<Element> recordListIterator = recordListElement.elementIterator(); |
| 91 | - List<RecordItem> recordList = new ArrayList<RecordItem>(); | |
| 92 | 86 | if (recordListIterator != null) { |
| 93 | - RecordItem record = new RecordItem(); | |
| 94 | - logger.info("处理录像列表数据..."); | |
| 87 | + List<RecordItem> recordList = new ArrayList<>(); | |
| 95 | 88 | // 遍历DeviceList |
| 96 | 89 | while (recordListIterator.hasNext()) { |
| 97 | 90 | Element itemRecord = recordListIterator.next(); |
| ... | ... | @@ -100,43 +93,31 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 100 | 93 | logger.info("记录为空,下一个..."); |
| 101 | 94 | continue; |
| 102 | 95 | } |
| 103 | - record = new RecordItem(); | |
| 96 | + RecordItem record = new RecordItem(); | |
| 104 | 97 | record.setDeviceId(getText(itemRecord, "DeviceID")); |
| 105 | 98 | record.setName(getText(itemRecord, "Name")); |
| 106 | 99 | record.setFilePath(getText(itemRecord, "FilePath")); |
| 107 | 100 | record.setFileSize(getText(itemRecord, "FileSize")); |
| 108 | 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 | 109 | record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 |
| 114 | 110 | : Integer.parseInt(getText(itemRecord, "Secrecy"))); |
| 115 | 111 | record.setType(getText(itemRecord, "Type")); |
| 116 | 112 | record.setRecorderId(getText(itemRecord, "RecorderID")); |
| 117 | 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 | 123 | } catch (SipException e) { |
| ... | ... | @@ -154,4 +135,20 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent |
| 154 | 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 | 89 | }); |
| 90 | 90 | |
| 91 | 91 | // 获取zlm信息 |
| 92 | - logger.info("[zlm接入]等待默认zlm中..."); | |
| 92 | + logger.info("[zlm] 等待默认zlm中..."); | |
| 93 | 93 | |
| 94 | 94 | // 获取所有的zlm, 并开启主动连接 |
| 95 | 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 | 39 | @Async |
| 40 | 40 | @EventListener |
| 41 | 41 | public void onApplicationEvent(ZLMOnlineEvent event) { |
| 42 | - | |
| 43 | - logger.info("【ZLM上线】ID:" + event.getMediaServerId()); | |
| 42 | + logger.info("[ZLM] 上线 ID:" + event.getMediaServerId()); | |
| 44 | 43 | streamPushService.zlmServerOnline(event.getMediaServerId()); |
| 45 | 44 | streamProxyService.zlmServerOnline(event.getMediaServerId()); |
| 46 | 45 | |
| ... | ... | @@ -50,7 +49,7 @@ public class ZLMStatusEventListener { |
| 50 | 49 | @EventListener |
| 51 | 50 | public void onApplicationEvent(ZLMOfflineEvent event) { |
| 52 | 51 | |
| 53 | - logger.info("ZLM离线事件触发,ID:" + event.getMediaServerId()); | |
| 52 | + logger.info("[ZLM] 离线,ID:" + event.getMediaServerId()); | |
| 54 | 53 | // 处理ZLM离线 |
| 55 | 54 | mediaServerService.zlmServerOffline(event.getMediaServerId()); |
| 56 | 55 | streamProxyService.zlmServerOffline(event.getMediaServerId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| ... | ... | @@ -44,7 +44,7 @@ public interface IMediaServerService { |
| 44 | 44 | |
| 45 | 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 | 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 | 11 | import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; |
| 12 | 12 | import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; |
| 13 | 13 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 14 | -import com.genersoft.iot.vmp.service.IMediaService; | |
| 15 | 14 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | 15 | import com.genersoft.iot.vmp.storager.dao.DeviceMapper; |
| 17 | 16 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 18 | 17 | import org.slf4j.Logger; |
| 19 | 18 | import org.slf4j.LoggerFactory; |
| 20 | 19 | import org.springframework.beans.factory.annotation.Autowired; |
| 21 | -import org.springframework.beans.factory.annotation.Qualifier; | |
| 22 | -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; | |
| 23 | 20 | import org.springframework.stereotype.Service; |
| 24 | 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 | 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 | 60 | |
| 67 | 61 | @Override |
| 68 | 62 | public void online(Device device) { |
| 69 | - logger.info("[设备上线],deviceId:" + device.getDeviceId()); | |
| 63 | + logger.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort()); | |
| 70 | 64 | Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId()); |
| 71 | 65 | Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId()); |
| 72 | 66 | |
| ... | ... | @@ -101,9 +95,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 101 | 95 | // 刷新过期任务 |
| 102 | 96 | String registerExpireTaskKey = registerExpireTaskKeyPrefix + device.getDeviceId(); |
| 103 | 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 | 101 | @Override |
| ... | ... | @@ -217,18 +209,9 @@ public class DeviceServiceImpl implements IDeviceService { |
| 217 | 209 | |
| 218 | 210 | @Override |
| 219 | 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 | 217 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -95,7 +95,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 95 | 95 | */ |
| 96 | 96 | @Override |
| 97 | 97 | public void updateVmServer(List<MediaServerItem> mediaServerItemList) { |
| 98 | - logger.info("[缓存初始化] Media Server "); | |
| 98 | + logger.info("[zlm] 缓存初始化 "); | |
| 99 | 99 | for (MediaServerItem mediaServerItem : mediaServerItemList) { |
| 100 | 100 | if (StringUtils.isEmpty(mediaServerItem.getId())) { |
| 101 | 101 | continue; |
| ... | ... | @@ -116,8 +116,8 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 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 | 123 | @Override |
| ... | ... | @@ -352,7 +352,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 352 | 352 | */ |
| 353 | 353 | @Override |
| 354 | 354 | public void zlmServerOnline(ZLMServerConfig zlmServerConfig) { |
| 355 | - logger.info("[ ZLM:{} ]-[ {}:{} ]正在连接", | |
| 355 | + logger.info("[ZLM] 正在连接 : {} -> {}:{}", | |
| 356 | 356 | zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); |
| 357 | 357 | |
| 358 | 358 | MediaServerItem serverItem = mediaServerMapper.queryOne(zlmServerConfig.getGeneralMediaServerId()); |
| ... | ... | @@ -405,7 +405,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 405 | 405 | setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); |
| 406 | 406 | } |
| 407 | 407 | publisher.zlmOnlineEventPublish(serverItem.getId()); |
| 408 | - logger.info("[ ZLM:{} ]-[ {}:{} ]连接成功", | |
| 408 | + logger.info("[ZLM] 连接成功 {} - {}:{} ", | |
| 409 | 409 | zlmServerConfig.getGeneralMediaServerId(), zlmServerConfig.getIp(), zlmServerConfig.getHttpPort()); |
| 410 | 410 | } |
| 411 | 411 | |
| ... | ... | @@ -483,7 +483,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 483 | 483 | */ |
| 484 | 484 | @Override |
| 485 | 485 | public void setZLMConfig(MediaServerItem mediaServerItem, boolean restart) { |
| 486 | - logger.info("[ ZLM:{} ]-[ {}:{} ]正在设置zlm", | |
| 486 | + logger.info("[ZLM] 正在设置 :{} -> {}:{}", | |
| 487 | 487 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); |
| 488 | 488 | String protocol = sslEnabled ? "https" : "http"; |
| 489 | 489 | String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); |
| ... | ... | @@ -527,17 +527,17 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 527 | 527 | |
| 528 | 528 | if (responseJSON != null && responseJSON.getInteger("code") == 0) { |
| 529 | 529 | if (restart) { |
| 530 | - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm成功, 开始重启以保证配置生效", | |
| 530 | + logger.info("[ZLM] 设置成功,开始重启以保证配置生效 {} -> {}:{}", | |
| 531 | 531 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); |
| 532 | 532 | zlmresTfulUtils.restartServer(mediaServerItem); |
| 533 | 533 | }else { |
| 534 | - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm成功", | |
| 534 | + logger.info("[ZLM] 设置成功 {} -> {}:{}", | |
| 535 | 535 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); |
| 536 | 536 | } |
| 537 | 537 | |
| 538 | 538 | |
| 539 | 539 | }else { |
| 540 | - logger.info("[ ZLM:{} ]-[ {}:{} ]设置zlm失败", | |
| 540 | + logger.info("[ZLM] 设置zlm失败 {} -> {}:{}", | |
| 541 | 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 | 193 | if (mediaServerItem.isRtpEnable()) { |
| 194 | 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 | 197 | play(mediaServerItem, ssrcInfo, device, channelId, (mediaServerItemInUse, response)->{ |
| 198 | 198 | if (hookEvent != null) { |
| 199 | 199 | hookEvent.response(mediaServerItem, response); |
| ... | ... | @@ -237,7 +237,7 @@ public class PlayServiceImpl implements IPlayService { |
| 237 | 237 | streamId = String.format("%s_%s", device.getDeviceId(), channelId); |
| 238 | 238 | } |
| 239 | 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 | 360 | return null; |
| 361 | 361 | } |
| 362 | 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 | 365 | return playBack(newMediaServerItem, ssrcInfo, deviceId, channelId, startTime, endTime, inviteStreamCallback, callback); |
| 366 | 366 | } |
| ... | ... | @@ -447,7 +447,7 @@ public class PlayServiceImpl implements IPlayService { |
| 447 | 447 | return null; |
| 448 | 448 | } |
| 449 | 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 | 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 | 1 | package com.genersoft.iot.vmp.utils; |
| 2 | 2 | |
| 3 | -import java.text.ParseException; | |
| 3 | + | |
| 4 | 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 | 13 | import java.util.Locale; |
| 7 | 14 | |
| 8 | 15 | /** |
| 9 | 16 | * 全局时间工具类 |
| 10 | - * @author swwheihei | |
| 17 | + * @author lin | |
| 11 | 18 | */ |
| 12 | 19 | public class DateUtil { |
| 13 | 20 | |
| 14 | 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 | 24 | public static final SimpleDateFormat formatISO8601 = new SimpleDateFormat(yyyy_MM_dd_T_HH_mm_ss_SSSXXX, Locale.getDefault()); |
| 18 | 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 | 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 | 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 | 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 | 5 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 6 | 6 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 7 | 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 | 10 | import io.swagger.annotations.Api; |
| 9 | 11 | import io.swagger.annotations.ApiImplicitParam; |
| 10 | 12 | import io.swagger.annotations.ApiImplicitParams; |
| ... | ... | @@ -27,6 +29,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 27 | 29 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 28 | 30 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 29 | 31 | |
| 32 | +import java.time.LocalDate; | |
| 30 | 33 | import java.util.UUID; |
| 31 | 34 | |
| 32 | 35 | @Api(tags = "国标录像") |
| ... | ... | @@ -60,15 +63,32 @@ public class GBRecordController { |
| 60 | 63 | @ApiImplicitParam(name = "endTime", value = "结束时间", dataTypeClass = String.class), |
| 61 | 64 | }) |
| 62 | 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 | 68 | if (logger.isDebugEnabled()) { |
| 66 | 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 | 90 | Device device = storager.queryVideoDevice(deviceId); |
| 70 | 91 | // 指定超时时间 1分钟30秒 |
| 71 | - DeferredResult<ResponseEntity<RecordInfo>> result = new DeferredResult<>(90*1000L); | |
| 72 | 92 | String uuid = UUID.randomUUID().toString(); |
| 73 | 93 | int sn = (int)((Math.random()*9+1)*100000); |
| 74 | 94 | String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; |
| ... | ... | @@ -76,7 +96,10 @@ public class GBRecordController { |
| 76 | 96 | msg.setId(uuid); |
| 77 | 97 | msg.setKey(key); |
| 78 | 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 | 103 | resultHolder.invokeResult(msg); |
| 81 | 104 | })); |
| 82 | 105 | |
| ... | ... | @@ -84,6 +107,10 @@ public class GBRecordController { |
| 84 | 107 | resultHolder.put(key, uuid, result); |
| 85 | 108 | result.onTimeout(()->{ |
| 86 | 109 | msg.setData("timeout"); |
| 110 | + WVPResult<RecordInfo> wvpResult = new WVPResult<>(); | |
| 111 | + wvpResult.setCode(-1); | |
| 112 | + wvpResult.setMsg("timeout"); | |
| 113 | + msg.setData(wvpResult); | |
| 87 | 114 | resultHolder.invokeResult(msg); |
| 88 | 115 | }); |
| 89 | 116 | return result; | ... | ... |
src/main/resources/all-application.yml
src/main/resources/application-dev.yml
src/main/resources/application-docker.yml
web_src/src/components/channelList.vue
| ... | ... | @@ -244,7 +244,7 @@ export default { |
| 244 | 244 | }); |
| 245 | 245 | }, |
| 246 | 246 | queryRecords: function (itemData) { |
| 247 | - var format = moment().format("YYYY-M-D"); | |
| 247 | + var format = moment().format("yyyy-MM-DD"); | |
| 248 | 248 | let deviceId = this.deviceId; |
| 249 | 249 | let channelId = itemData.channelId; |
| 250 | 250 | this.$refs.devicePlayer.openDialog("record", deviceId, channelId, {date: format}) | ... | ... |
web_src/src/components/dialog/devicePlayer.vue
| ... | ... | @@ -453,9 +453,19 @@ export default { |
| 453 | 453 | method: 'get', |
| 454 | 454 | url: '/api/gb_record/query/' + this.deviceId + '/' + this.channelId + '?startTime=' + startTime + '&endTime=' + endTime |
| 455 | 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 | 469 | }).catch(function (e) { |
| 460 | 470 | console.log(e.message); |
| 461 | 471 | // that.videoHistory.searchHistoryResult = falsificationData.recordData; |
| ... | ... | @@ -671,7 +681,11 @@ export default { |
| 671 | 681 | this.$axios({ |
| 672 | 682 | method: 'get', |
| 673 | 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