Commit 9a96597e666fa32caefcfff5246b4cb722e9b1bc
Merge branch 'wvp-28181-2.0' into main-dev
# Conflicts: # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java # src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java # src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java # src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java # src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java # src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java # src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java # src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
Showing
84 changed files
with
2088 additions
and
651 deletions
Too many changes to show.
To preserve performance only 84 of 116 files are displayed.
libs/jdbc-x86/bcprov-jdk15on-1.70.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jre6.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/kingbase8-8.6.0.jre7.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jre6.jar
0 → 100644
No preview for this file type
libs/jdbc-x86/postgresql-42.2.9.jre7.jar
0 → 100644
No preview for this file type
pom.xml
| ... | ... | @@ -11,7 +11,7 @@ |
| 11 | 11 | |
| 12 | 12 | <groupId>com.genersoft</groupId> |
| 13 | 13 | <artifactId>wvp-pro</artifactId> |
| 14 | - <version>2.6.9</version> | |
| 14 | + <version>2.7.0</version> | |
| 15 | 15 | <name>web video platform</name> |
| 16 | 16 | <description>国标28181视频平台</description> |
| 17 | 17 | <packaging>${project.packaging}</packaging> |
| ... | ... | @@ -143,17 +143,24 @@ |
| 143 | 143 | <version>42.5.1</version> |
| 144 | 144 | </dependency> |
| 145 | 145 | |
| 146 | - <!-- kingbase人大金仓 --> | |
| 147 | - <!-- 手动下载驱动后安装 --> | |
| 148 | - <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 | |
| 149 | - -Dversion=8.6.0 -Dpackaging=jar --> | |
| 150 | - <dependency> | |
| 151 | - <groupId>com.kingbase</groupId> | |
| 152 | - <artifactId>kingbase8</artifactId> | |
| 153 | - <version>8.6.0</version> | |
| 154 | - <scope>system</scope> | |
| 155 | - <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> | |
| 156 | - </dependency> | |
| 146 | + <!-- kingbase人大金仓 --> | |
| 147 | + <!-- 手动下载驱动后安装 --> | |
| 148 | + <!-- mvn install:install-file -Dfile=/home/lin/soft/kingbase/jdbc-aarch/kingbase8-8.6.0.jar -DgroupId=com.kingbase -DartifactId=kingbase8 -Dversion=8.6.0 -Dpackaging=jar | |
| 149 | + --> | |
| 150 | + <dependency> | |
| 151 | + <groupId>com.kingbase</groupId> | |
| 152 | + <artifactId>kingbase8</artifactId> | |
| 153 | + <version>8.6.0</version> | |
| 154 | + <scope>system</scope> | |
| 155 | + <systemPath>${basedir}/libs/jdbc-aarch/kingbase8-8.6.0.jar</systemPath> | |
| 156 | + </dependency> | |
| 157 | + <dependency> | |
| 158 | + <groupId>com.kingbase</groupId> | |
| 159 | + <artifactId>kingbase8</artifactId> | |
| 160 | + <version>8.6.0</version> | |
| 161 | + <scope>system</scope> | |
| 162 | + <systemPath>${basedir}/libs/jdbc-x86/kingbase8-8.6.0.jar</systemPath> | |
| 163 | + </dependency> | |
| 157 | 164 | |
| 158 | 165 | <!--Mybatis分页插件 --> |
| 159 | 166 | <dependency> |
| ... | ... | @@ -163,21 +170,16 @@ |
| 163 | 170 | </dependency> |
| 164 | 171 | |
| 165 | 172 | <!--在线文档 --> |
| 173 | + <!--在线文档 --> | |
| 166 | 174 | <dependency> |
| 167 | 175 | <groupId>org.springdoc</groupId> |
| 168 | 176 | <artifactId>springdoc-openapi-ui</artifactId> |
| 169 | - <version>1.7.0</version> | |
| 170 | - <exclusions> | |
| 171 | - <exclusion> | |
| 172 | - <groupId>org.yaml</groupId> | |
| 173 | - <artifactId>snakeyaml</artifactId> | |
| 174 | - </exclusion> | |
| 175 | - </exclusions> | |
| 177 | + <version>1.6.10</version> | |
| 176 | 178 | </dependency> |
| 177 | 179 | <dependency> |
| 178 | - <groupId>org.yaml</groupId> | |
| 179 | - <artifactId>snakeyaml</artifactId> | |
| 180 | - <version>2.2</version> | |
| 180 | + <groupId>org.springdoc</groupId> | |
| 181 | + <artifactId>springdoc-openapi-security</artifactId> | |
| 182 | + <version>1.6.10</version> | |
| 181 | 183 | </dependency> |
| 182 | 184 | |
| 183 | 185 | <dependency> | ... | ... |
sql/2.6.9更新.sql deleted
100644 → 0
src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java
| 1 | 1 | package com.genersoft.iot.vmp.common; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 3 | 4 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | 5 | |
| 5 | 6 | import java.io.Serializable; |
| ... | ... | @@ -76,6 +77,8 @@ public class StreamInfo implements Serializable, Cloneable{ |
| 76 | 77 | private String endTime; |
| 77 | 78 | @Schema(description = "进度(录像下载使用)") |
| 78 | 79 | private double progress; |
| 80 | + @Schema(description = "文件下载地址(录像下载使用)") | |
| 81 | + private DownloadFileInfo downLoadFilePath; | |
| 79 | 82 | |
| 80 | 83 | @Schema(description = "是否暂停(录像回放使用)") |
| 81 | 84 | private boolean pause; |
| ... | ... | @@ -605,5 +608,11 @@ public class StreamInfo implements Serializable, Cloneable{ |
| 605 | 608 | this.subStream = subStream; |
| 606 | 609 | } |
| 607 | 610 | |
| 611 | + public DownloadFileInfo getDownLoadFilePath() { | |
| 612 | + return downLoadFilePath; | |
| 613 | + } | |
| 608 | 614 | |
| 615 | + public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) { | |
| 616 | + this.downLoadFilePath = downLoadFilePath; | |
| 617 | + } | |
| 609 | 618 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java
| ... | ... | @@ -53,7 +53,7 @@ public class VideoManagerConstants { |
| 53 | 53 | |
| 54 | 54 | public static final String MEDIA_TRANSACTION_USED_PREFIX = "VMP_MEDIA_TRANSACTION_"; |
| 55 | 55 | |
| 56 | - public static final String MEDIA_STREAM_AUTHORITY = "MEDIA_STREAM_AUTHORITY_"; | |
| 56 | + public static final String MEDIA_STREAM_AUTHORITY = "VMP_MEDIA_STREAM_AUTHORITY_"; | |
| 57 | 57 | |
| 58 | 58 | public static final String SIP_CSEQ_PREFIX = "VMP_SIP_CSEQ_"; |
| 59 | 59 | |
| ... | ... | @@ -71,6 +71,7 @@ public class VideoManagerConstants { |
| 71 | 71 | public static final String BROADCAST_WAITE_INVITE = "task_broadcast_waite_invite_"; |
| 72 | 72 | |
| 73 | 73 | public static final String REGISTER_EXPIRE_TASK_KEY_PREFIX = "VMP_device_register_expire_"; |
| 74 | + public static final String PUSH_STREAM_LIST = "VMP_PUSH_STREAM_LIST_"; | |
| 74 | 75 | |
| 75 | 76 | |
| 76 | 77 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/CloudRecordTimer.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.conf; | |
| 2 | + | |
| 3 | + | |
| 4 | +import com.alibaba.fastjson2.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; | |
| 6 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 7 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 8 | +import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 9 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | |
| 10 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | |
| 11 | +import com.genersoft.iot.vmp.vmanager.cloudRecord.CloudRecordController; | |
| 12 | +import org.slf4j.Logger; | |
| 13 | +import org.slf4j.LoggerFactory; | |
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 15 | +import org.springframework.scheduling.annotation.Scheduled; | |
| 16 | +import org.springframework.stereotype.Component; | |
| 17 | + | |
| 18 | +import java.io.File; | |
| 19 | +import java.util.ArrayList; | |
| 20 | +import java.util.Calendar; | |
| 21 | +import java.util.Date; | |
| 22 | +import java.util.List; | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * 录像文件定时删除 | |
| 26 | + */ | |
| 27 | +@Component | |
| 28 | +public class CloudRecordTimer { | |
| 29 | + | |
| 30 | + private final static Logger logger = LoggerFactory.getLogger(CloudRecordTimer.class); | |
| 31 | + | |
| 32 | + @Autowired | |
| 33 | + private IMediaServerService mediaServerService; | |
| 34 | + | |
| 35 | + @Autowired | |
| 36 | + private CloudRecordServiceMapper cloudRecordServiceMapper; | |
| 37 | + | |
| 38 | + @Autowired | |
| 39 | + private ZLMRESTfulUtils zlmresTfulUtils; | |
| 40 | + | |
| 41 | + /** | |
| 42 | + * 定时查询待删除的录像文件 | |
| 43 | + */ | |
| 44 | +// @Scheduled(fixedRate = 10000) //每五秒执行一次,方便测试 | |
| 45 | + @Scheduled(cron = "0 0 0 * * ?") //每天的0点执行 | |
| 46 | + public void execute(){ | |
| 47 | + logger.info("[录像文件定时清理] 开始清理过期录像文件"); | |
| 48 | + // 获取配置了assist的流媒体节点 | |
| 49 | + List<MediaServerItem> mediaServerItemList = mediaServerService.getAllOnline(); | |
| 50 | + if (mediaServerItemList.isEmpty()) { | |
| 51 | + return; | |
| 52 | + } | |
| 53 | + long result = 0; | |
| 54 | + for (MediaServerItem mediaServerItem : mediaServerItemList) { | |
| 55 | + | |
| 56 | + Calendar lastCalendar = Calendar.getInstance(); | |
| 57 | + if (mediaServerItem.getRecordDay() > 0) { | |
| 58 | + lastCalendar.setTime(new Date()); | |
| 59 | + // 获取保存的最后截至日[期,因为每个节点都有一个日期,也就是支持每个节点设置不同的保存日期, | |
| 60 | + lastCalendar.add(Calendar.DAY_OF_MONTH, -mediaServerItem.getRecordDay()); | |
| 61 | + Long lastDate = lastCalendar.getTimeInMillis(); | |
| 62 | + | |
| 63 | + // 获取到截至日期之前的录像文件列表,文件列表满足未被收藏和保持的。这两个字段目前共能一致, | |
| 64 | + // 为我自己业务系统相关的代码,大家使用的时候直接使用收藏(collect)这一个类型即可 | |
| 65 | + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.queryRecordListForDelete(lastDate, mediaServerItem.getId()); | |
| 66 | + if (cloudRecordItemList.isEmpty()) { | |
| 67 | + continue; | |
| 68 | + } | |
| 69 | + // TODO 后续可以删除空了的过期日期文件夹 | |
| 70 | + for (CloudRecordItem cloudRecordItem : cloudRecordItemList) { | |
| 71 | + String date = new File(cloudRecordItem.getFilePath()).getParentFile().getName(); | |
| 72 | + JSONObject jsonObject = zlmresTfulUtils.deleteRecordDirectory(mediaServerItem, cloudRecordItem.getApp(), | |
| 73 | + cloudRecordItem.getStream(), date, cloudRecordItem.getFileName()); | |
| 74 | + if (jsonObject.getInteger("code") != 0) { | |
| 75 | + logger.warn("[录像文件定时清理] 删除磁盘文件错误: {}:{}", cloudRecordItem.getFilePath(), jsonObject); | |
| 76 | + } | |
| 77 | + } | |
| 78 | + result += cloudRecordServiceMapper.deleteList(cloudRecordItemList); | |
| 79 | + } | |
| 80 | + } | |
| 81 | + logger.info("[录像文件定时清理] 共清理{}个过期录像文件", result); | |
| 82 | + } | |
| 83 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/MediaConfig.java
| ... | ... | @@ -81,6 +81,12 @@ public class MediaConfig{ |
| 81 | 81 | @Value("${media.record-assist-port:0}") |
| 82 | 82 | private Integer recordAssistPort = 0; |
| 83 | 83 | |
| 84 | + @Value("${media.record-day:7}") | |
| 85 | + private Integer recordDay; | |
| 86 | + | |
| 87 | + @Value("${media.record-path:}") | |
| 88 | + private String recordPath; | |
| 89 | + | |
| 84 | 90 | public String getId() { |
| 85 | 91 | return id; |
| 86 | 92 | } |
| ... | ... | @@ -212,13 +218,32 @@ public class MediaConfig{ |
| 212 | 218 | mediaServerItem.setSendRtpPortRange(rtpSendPortRange); |
| 213 | 219 | mediaServerItem.setRecordAssistPort(recordAssistPort); |
| 214 | 220 | mediaServerItem.setHookAliveInterval(30.00f); |
| 215 | - | |
| 221 | + mediaServerItem.setRecordDay(recordDay); | |
| 222 | + if (recordPath != null) { | |
| 223 | + mediaServerItem.setRecordPath(recordPath); | |
| 224 | + } | |
| 216 | 225 | mediaServerItem.setCreateTime(DateUtil.getNow()); |
| 217 | 226 | mediaServerItem.setUpdateTime(DateUtil.getNow()); |
| 218 | 227 | |
| 219 | 228 | return mediaServerItem; |
| 220 | 229 | } |
| 221 | 230 | |
| 231 | + public Integer getRecordDay() { | |
| 232 | + return recordDay; | |
| 233 | + } | |
| 234 | + | |
| 235 | + public void setRecordDay(Integer recordDay) { | |
| 236 | + this.recordDay = recordDay; | |
| 237 | + } | |
| 238 | + | |
| 239 | + public String getRecordPath() { | |
| 240 | + return recordPath; | |
| 241 | + } | |
| 242 | + | |
| 243 | + public void setRecordPath(String recordPath) { | |
| 244 | + this.recordPath = recordPath; | |
| 245 | + } | |
| 246 | + | |
| 222 | 247 | public String getRtpSendPortRange() { |
| 223 | 248 | return rtpSendPortRange; |
| 224 | 249 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SpringDocConfig.java
| 1 | 1 | package com.genersoft.iot.vmp.conf; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 4 | +import io.swagger.v3.oas.models.Components; | |
| 3 | 5 | import io.swagger.v3.oas.models.OpenAPI; |
| 4 | 6 | import io.swagger.v3.oas.models.info.Contact; |
| 5 | 7 | import io.swagger.v3.oas.models.info.Info; |
| 6 | 8 | import io.swagger.v3.oas.models.info.License; |
| 9 | +import io.swagger.v3.oas.models.security.SecurityScheme; | |
| 7 | 10 | import org.springframework.core.annotation.Order; |
| 8 | 11 | import org.springdoc.core.GroupedOpenApi; |
| 9 | 12 | import org.springframework.beans.factory.annotation.Value; |
| ... | ... | @@ -26,10 +29,14 @@ public class SpringDocConfig { |
| 26 | 29 | contact.setName("pan"); |
| 27 | 30 | contact.setEmail("648540858@qq.com"); |
| 28 | 31 | return new OpenAPI() |
| 32 | + .components(new Components() | |
| 33 | + .addSecuritySchemes(JwtUtils.HEADER, new SecurityScheme() | |
| 34 | + .type(SecurityScheme.Type.HTTP) | |
| 35 | + .bearerFormat("JWT"))) | |
| 29 | 36 | .info(new Info().title("WVP-PRO 接口文档") |
| 30 | 37 | .contact(contact) |
| 31 | 38 | .description("开箱即用的28181协议视频平台") |
| 32 | - .version("v2.0") | |
| 39 | + .version("v3.1.0") | |
| 33 | 40 | .license(new License().name("Apache 2.0").url("http://springdoc.org"))); |
| 34 | 41 | } |
| 35 | 42 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/SystemInfoTimerTask.java
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
| ... | ... | @@ -56,8 +56,6 @@ public class UserSetting { |
| 56 | 56 | |
| 57 | 57 | private String serverId = "000000"; |
| 58 | 58 | |
| 59 | - private String recordPath = null; | |
| 60 | - | |
| 61 | 59 | private String thirdPartyGBIdReg = "[\\s\\S]*"; |
| 62 | 60 | |
| 63 | 61 | private String broadcastForPlatform = "UDP"; |
| ... | ... | @@ -262,14 +260,6 @@ public class UserSetting { |
| 262 | 260 | this.refuseChannelStatusChannelFormNotify = refuseChannelStatusChannelFormNotify; |
| 263 | 261 | } |
| 264 | 262 | |
| 265 | - public String getRecordPath() { | |
| 266 | - return recordPath; | |
| 267 | - } | |
| 268 | - | |
| 269 | - public void setRecordPath(String recordPath) { | |
| 270 | - this.recordPath = recordPath; | |
| 271 | - } | |
| 272 | - | |
| 273 | 263 | public int getMaxNotifyCountQueue() { |
| 274 | 264 | return maxNotifyCountQueue; |
| 275 | 265 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
| ... | ... | @@ -28,7 +28,7 @@ public class JwtUtils implements InitializingBean { |
| 28 | 28 | |
| 29 | 29 | private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class); |
| 30 | 30 | |
| 31 | - private static final String HEADER = "access-token"; | |
| 31 | + public static final String HEADER = "access-token"; | |
| 32 | 32 | |
| 33 | 33 | private static final String AUDIENCE = "Audience"; |
| 34 | 34 | ... | ... |
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
| ... | ... | @@ -68,6 +68,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 68 | 68 | matchers.add("/"); |
| 69 | 69 | matchers.add("/#/**"); |
| 70 | 70 | matchers.add("/static/**"); |
| 71 | + matchers.add("/swagger-ui.html"); | |
| 72 | + matchers.add("/swagger-ui/"); | |
| 71 | 73 | matchers.add("/index.html"); |
| 72 | 74 | matchers.add("/doc.html"); |
| 73 | 75 | matchers.add("/webjars/**"); |
| ... | ... | @@ -77,7 +79,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 77 | 79 | matchers.add("/api/device/query/snap/**"); |
| 78 | 80 | matchers.add("/record_proxy/*/**"); |
| 79 | 81 | matchers.add("/api/emit"); |
| 80 | - matchers.addAll(userSetting.getInterfaceAuthenticationExcludes()); | |
| 82 | + matchers.add("/favicon.ico"); | |
| 81 | 83 | // 可以直接访问的静态数据 |
| 82 | 84 | web.ignoring().antMatchers(matchers.toArray(new String[0])); |
| 83 | 85 | } |
| ... | ... | @@ -114,7 +116,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { |
| 114 | 116 | .authorizeRequests() |
| 115 | 117 | .requestMatchers(CorsUtils::isPreFlightRequest).permitAll() |
| 116 | 118 | .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll() |
| 117 | - .antMatchers("/api/user/login", "/index/hook/**").permitAll() | |
| 119 | + .antMatchers("/api/user/login", "/index/hook/**", "/swagger-ui/**", "/doc.html").permitAll() | |
| 118 | 120 | .anyRequest().authenticated() |
| 119 | 121 | // 异常处理器 |
| 120 | 122 | .and() | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java
| ... | ... | @@ -148,13 +148,13 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 148 | 148 | if (event.getDeviceChannels() != null) { |
| 149 | 149 | deviceChannelList.addAll(event.getDeviceChannels()); |
| 150 | 150 | } |
| 151 | - if (event.getGbStreams() != null && event.getGbStreams().size() > 0){ | |
| 151 | + if (event.getGbStreams() != null && !event.getGbStreams().isEmpty()){ | |
| 152 | 152 | for (GbStream gbStream : event.getGbStreams()) { |
| 153 | 153 | deviceChannelList.add( |
| 154 | 154 | gbStreamService.getDeviceChannelListByStreamWithStatus(gbStream, gbStream.getCatalogId(), parentPlatform)); |
| 155 | 155 | } |
| 156 | 156 | } |
| 157 | - if (deviceChannelList.size() > 0) { | |
| 157 | + if (!deviceChannelList.isEmpty()) { | |
| 158 | 158 | logger.info("[Catalog事件: {}]平台:{},影响通道{}个", event.getType(), event.getPlatformId(), deviceChannelList.size()); |
| 159 | 159 | try { |
| 160 | 160 | sipCommanderFroPlatform.sendNotifyForCatalogAddOrUpdate(event.getType(), parentPlatform, deviceChannelList, subscribe, null); |
| ... | ... | @@ -163,10 +163,10 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> { |
| 163 | 163 | logger.error("[命令发送失败] 国标级联 Catalog通知: {}", e.getMessage()); |
| 164 | 164 | } |
| 165 | 165 | } |
| 166 | - }else if (parentPlatformMap.keySet().size() > 0) { | |
| 166 | + }else if (!parentPlatformMap.keySet().isEmpty()) { | |
| 167 | 167 | for (String gbId : parentPlatformMap.keySet()) { |
| 168 | 168 | List<ParentPlatform> parentPlatforms = parentPlatformMap.get(gbId); |
| 169 | - if (parentPlatforms != null && parentPlatforms.size() > 0) { | |
| 169 | + if (parentPlatforms != null && !parentPlatforms.isEmpty()) { | |
| 170 | 170 | for (ParentPlatform platform : parentPlatforms) { |
| 171 | 171 | SubscribeInfo subscribeInfo = subscribeHolder.getCatalogSubscribe(platform.getServerGBId()); |
| 172 | 172 | if (subscribeInfo == null) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/session/VideoStreamSessionManager.java
| ... | ... | @@ -75,6 +75,33 @@ public class VideoStreamSessionManager { |
| 75 | 75 | return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); |
| 76 | 76 | } |
| 77 | 77 | |
| 78 | + public SsrcTransaction getSsrcTransactionByCallId(String callId){ | |
| 79 | + | |
| 80 | + if (ObjectUtils.isEmpty(callId)) { | |
| 81 | + return null; | |
| 82 | + } | |
| 83 | + String key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_" + callId+ "_*"; | |
| 84 | + List<Object> scanResult = RedisUtil.scan(redisTemplate, key); | |
| 85 | + if (!scanResult.isEmpty()) { | |
| 86 | + return (SsrcTransaction)redisTemplate.opsForValue().get(scanResult.get(0)); | |
| 87 | + }else { | |
| 88 | + key = VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_*_*_play_*"; | |
| 89 | + scanResult = RedisUtil.scan(redisTemplate, key); | |
| 90 | + if (scanResult.isEmpty()) { | |
| 91 | + return null; | |
| 92 | + } | |
| 93 | + for (Object keyObj : scanResult) { | |
| 94 | + SsrcTransaction ssrcTransaction = (SsrcTransaction)redisTemplate.opsForValue().get(keyObj); | |
| 95 | + if (ssrcTransaction.getSipTransactionInfo() != null && | |
| 96 | + ssrcTransaction.getSipTransactionInfo().getCallId().equals(callId)) { | |
| 97 | + return ssrcTransaction; | |
| 98 | + } | |
| 99 | + } | |
| 100 | + return null; | |
| 101 | + } | |
| 102 | + | |
| 103 | + } | |
| 104 | + | |
| 78 | 105 | public List<SsrcTransaction> getSsrcTransactionForAll(String deviceId, String channelId, String callId, String stream){ |
| 79 | 106 | if (ObjectUtils.isEmpty(deviceId)) { |
| 80 | 107 | deviceId ="*"; |
| ... | ... | @@ -117,8 +144,19 @@ public class VideoStreamSessionManager { |
| 117 | 144 | } |
| 118 | 145 | |
| 119 | 146 | public void remove(String deviceId, String channelId, String stream) { |
| 120 | - SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, null, stream); | |
| 121 | - if (ssrcTransaction == null) { | |
| 147 | + List<SsrcTransaction> ssrcTransactionList = getSsrcTransactionForAll(deviceId, channelId, null, stream); | |
| 148 | + if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) { | |
| 149 | + return; | |
| 150 | + } | |
| 151 | + for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { | |
| 152 | + redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | |
| 153 | + + deviceId + "_" + channelId + "_" + ssrcTransaction.getCallId() + "_" + ssrcTransaction.getStream()); | |
| 154 | + } | |
| 155 | + } | |
| 156 | + | |
| 157 | + public void removeByCallId(String deviceId, String channelId, String callId) { | |
| 158 | + SsrcTransaction ssrcTransaction = getSsrcTransaction(deviceId, channelId, callId, null); | |
| 159 | + if (ssrcTransaction == null ) { | |
| 122 | 160 | return; |
| 123 | 161 | } |
| 124 | 162 | redisTemplate.delete(VideoManagerConstants.MEDIA_TRANSACTION_USED_PREFIX + userSetting.getServerId() + "_" | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
| ... | ... | @@ -164,6 +164,7 @@ public class SIPRequestHeaderProvider { |
| 164 | 164 | Request request = null; |
| 165 | 165 | //请求行 |
| 166 | 166 | SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, device.getHostAddress()); |
| 167 | +// SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress()); | |
| 167 | 168 | // via |
| 168 | 169 | ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>(); |
| 169 | 170 | ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag()); |
| ... | ... | @@ -174,6 +175,7 @@ public class SIPRequestHeaderProvider { |
| 174 | 175 | FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag()); |
| 175 | 176 | //to |
| 176 | 177 | SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId,device.getHostAddress()); |
| 178 | +// SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(device.getDeviceId(),device.getHostAddress()); | |
| 177 | 179 | Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI); |
| 178 | 180 | ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress, transactionInfo.getToTag()); |
| 179 | 181 | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java
| ... | ... | @@ -40,6 +40,8 @@ import javax.sip.SipFactory; |
| 40 | 40 | import javax.sip.header.CallIdHeader; |
| 41 | 41 | import javax.sip.message.Request; |
| 42 | 42 | import java.text.ParseException; |
| 43 | +import java.util.ArrayList; | |
| 44 | +import java.util.List; | |
| 43 | 45 | |
| 44 | 46 | /** |
| 45 | 47 | * @description:设备能力接口,用于定义设备的控制、查询能力 |
| ... | ... | @@ -677,22 +679,21 @@ public class SIPCommander implements ISIPCommander { |
| 677 | 679 | */ |
| 678 | 680 | @Override |
| 679 | 681 | public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { |
| 680 | - SsrcTransaction ssrcTransaction; | |
| 681 | - if (callId != null) { | |
| 682 | - ssrcTransaction = streamSession.getSsrcTransaction(null, null, callId, null); | |
| 683 | - }else { | |
| 684 | - ssrcTransaction = streamSession.getSsrcTransaction(device.getDeviceId(), channelId, null, stream); | |
| 685 | - } | |
| 686 | - if (ssrcTransaction == null) { | |
| 682 | + List<SsrcTransaction> ssrcTransactionList = streamSession.getSsrcTransactionForAll(device.getDeviceId(), channelId, callId, stream); | |
| 683 | + if (ssrcTransactionList == null || ssrcTransactionList.isEmpty()) { | |
| 684 | + logger.info("[发送BYE] 未找到事务信息,设备: device: {}, channel: {}", device.getDeviceId(), channelId); | |
| 687 | 685 | throw new SsrcTransactionNotFoundException(device.getDeviceId(), channelId, callId, stream); |
| 688 | 686 | } |
| 689 | 687 | |
| 690 | - mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | |
| 691 | - mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | |
| 692 | - streamSession.remove(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | |
| 688 | + for (SsrcTransaction ssrcTransaction : ssrcTransactionList) { | |
| 689 | + logger.info("[发送BYE] 设备: device: {}, channel: {}, callId: {}", device.getDeviceId(), channelId, ssrcTransaction.getCallId()); | |
| 690 | + mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); | |
| 693 | 691 | |
| 694 | - Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | |
| 695 | - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | |
| 692 | + mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); | |
| 693 | + streamSession.removeByCallId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId(), ssrcTransaction.getCallId()); | |
| 694 | + Request byteRequest = headerProvider.createByteRequest(device, channelId, ssrcTransaction.getSipTransactionInfo()); | |
| 695 | + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), byteRequest, null, okEvent); | |
| 696 | + } | |
| 696 | 697 | } |
| 697 | 698 | |
| 698 | 699 | @Override | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderFroPlatform.java
| ... | ... | @@ -579,7 +579,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 579 | 579 | |
| 580 | 580 | @Override |
| 581 | 581 | public void sendNotifyForCatalogAddOrUpdate(String type, ParentPlatform parentPlatform, List<DeviceChannel> deviceChannels, SubscribeInfo subscribeInfo, Integer index) throws InvalidArgumentException, ParseException, NoSuchFieldException, SipException, IllegalAccessException { |
| 582 | - if (parentPlatform == null || deviceChannels == null || deviceChannels.size() == 0 || subscribeInfo == null) { | |
| 582 | + if (parentPlatform == null || deviceChannels == null || deviceChannels.isEmpty() || subscribeInfo == null) { | |
| 583 | 583 | return; |
| 584 | 584 | } |
| 585 | 585 | if (index == null) { |
| ... | ... | @@ -597,6 +597,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 597 | 597 | Integer finalIndex = index; |
| 598 | 598 | String catalogXmlContent = getCatalogXmlContentForCatalogAddOrUpdate(parentPlatform, channels, |
| 599 | 599 | deviceChannels.size(), type, subscribeInfo); |
| 600 | + logger.info("[发送NOTIFY通知]类型: {},发送数量: {}", type, channels.size()); | |
| 600 | 601 | sendNotify(parentPlatform, catalogXmlContent, subscribeInfo, eventResult -> { |
| 601 | 602 | logger.error("发送NOTIFY通知消息失败。错误:{} {}", eventResult.statusCode, eventResult.msg); |
| 602 | 603 | }, (eventResult -> { |
| ... | ... | @@ -620,7 +621,7 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 620 | 621 | |
| 621 | 622 | SIPRequest notifyRequest = headerProviderPlatformProvider.createNotifyRequest(parentPlatform, catalogXmlContent, subscribeInfo); |
| 622 | 623 | |
| 623 | - sipSender.transmitRequest(parentPlatform.getDeviceIp(), notifyRequest); | |
| 624 | + sipSender.transmitRequest(parentPlatform.getDeviceIp(), notifyRequest, errorEvent, okEvent); | |
| 624 | 625 | } |
| 625 | 626 | |
| 626 | 627 | private String getCatalogXmlContentForCatalogAddOrUpdate(ParentPlatform parentPlatform, List<DeviceChannel> channels, int sumNum, String type, SubscribeInfo subscribeInfo) { |
| ... | ... | @@ -632,9 +633,9 @@ public class SIPCommanderFroPlatform implements ISIPCommanderForPlatform { |
| 632 | 633 | .append("<CmdType>Catalog</CmdType>\r\n") |
| 633 | 634 | .append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n") |
| 634 | 635 | .append("<DeviceID>" + parentPlatform.getDeviceGBId() + "</DeviceID>\r\n") |
| 635 | - .append("<SumNum>1</SumNum>\r\n") | |
| 636 | + .append("<SumNum>"+ sumNum +"</SumNum>\r\n") | |
| 636 | 637 | .append("<DeviceList Num=\"" + channels.size() + "\">\r\n"); |
| 637 | - if (channels.size() > 0) { | |
| 638 | + if (!channels.isEmpty()) { | |
| 638 | 639 | for (DeviceChannel channel : channels) { |
| 639 | 640 | if (parentPlatform.getServerGBId().equals(channel.getParentId())) { |
| 640 | 641 | channel.setParentId(parentPlatform.getDeviceGBId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java
| ... | ... | @@ -33,6 +33,7 @@ import javax.sip.header.CallIdHeader; |
| 33 | 33 | import javax.sip.message.Response; |
| 34 | 34 | import java.text.ParseException; |
| 35 | 35 | import java.util.HashMap; |
| 36 | +import java.util.List; | |
| 36 | 37 | import java.util.Map; |
| 37 | 38 | |
| 38 | 39 | /** |
| ... | ... | @@ -167,14 +168,12 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 167 | 168 | } |
| 168 | 169 | } |
| 169 | 170 | |
| 170 | - // 发流端发送的停止 | |
| 171 | - SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(null, null, callIdHeader.getCallId(), null); | |
| 172 | - if (ssrcTransaction == null ) { | |
| 173 | - logger.info("[收到bye] 但是无法获取推流信息和发流信息,忽略此请求"); | |
| 174 | - logger.info(request.toString()); | |
| 175 | - return; | |
| 176 | - } | |
| 177 | - | |
| 171 | + // 可能是设备发送的停止 | |
| 172 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransactionByCallId(callIdHeader.getCallId()); | |
| 173 | + if (ssrcTransaction == null) { | |
| 174 | + return; | |
| 175 | + } | |
| 176 | + logger.info("[收到bye] 来自设备:{}, 通道已停止推流: {}", ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | |
| 178 | 177 | |
| 179 | 178 | ParentPlatform platform = platformService.queryPlatformByServerGBId(ssrcTransaction.getDeviceId()); |
| 180 | 179 | if (platform != null ) { |
| ... | ... | @@ -216,7 +215,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In |
| 216 | 215 | if (mediaServerItem != null) { |
| 217 | 216 | mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcTransaction.getSsrc()); |
| 218 | 217 | } |
| 219 | - streamSession.remove(device.getDeviceId(), channel.getChannelId(), ssrcTransaction.getStream()); | |
| 218 | + streamSession.removeByCallId(device.getDeviceId(), channel.getChannelId(), ssrcTransaction.getCallId()); | |
| 220 | 219 | if (ssrcTransaction.getType() == InviteSessionType.BROADCAST) { |
| 221 | 220 | // 查找来源的对讲设备,发送停止 |
| 222 | 221 | Device sourceDevice = storager.queryVideoDeviceByPlatformIdAndChannelId(ssrcTransaction.getDeviceId(), ssrcTransaction.getChannelId()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java
| ... | ... | @@ -152,7 +152,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 152 | 152 | String requesterId = SipUtils.getUserIdFromFromHeader(request); |
| 153 | 153 | CallIdHeader callIdHeader = (CallIdHeader) request.getHeader(CallIdHeader.NAME); |
| 154 | 154 | if (requesterId == null || channelId == null) { |
| 155 | - logger.info("无法从FromHeader的Address中获取到平台id,返回400"); | |
| 155 | + logger.info("无法从请求中获取到平台id,返回400"); | |
| 156 | 156 | // 参数不全, 发400,请求错误 |
| 157 | 157 | try { |
| 158 | 158 | responseAck(request, Response.BAD_REQUEST); |
| ... | ... | @@ -745,13 +745,10 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 745 | 745 | dynamicTask.startDelay(callIdHeader.getCallId(), () -> { |
| 746 | 746 | logger.info("[ app={}, stream={} ] 等待设备开始推流超时", gbStream.getApp(), gbStream.getStream()); |
| 747 | 747 | try { |
| 748 | + redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream()); | |
| 748 | 749 | mediaListManager.removedChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream()); |
| 749 | 750 | responseAck(request, Response.REQUEST_TIMEOUT); // 超时 |
| 750 | - } catch (SipException e) { | |
| 751 | - logger.error("未处理的异常 ", e); | |
| 752 | - } catch (InvalidArgumentException e) { | |
| 753 | - logger.error("未处理的异常 ", e); | |
| 754 | - } catch (ParseException e) { | |
| 751 | + } catch (SipException | InvalidArgumentException | ParseException e) { | |
| 755 | 752 | logger.error("未处理的异常 ", e); |
| 756 | 753 | } |
| 757 | 754 | }, userSetting.getPlatformPlayTimeout()); |
| ... | ... | @@ -762,6 +759,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements |
| 762 | 759 | // 添加在本机上线的通知 |
| 763 | 760 | mediaListManager.addChannelOnlineEventLister(gbStream.getApp(), gbStream.getStream(), (app, stream, serverId) -> { |
| 764 | 761 | dynamicTask.stop(callIdHeader.getCallId()); |
| 762 | + redisPushStreamResponseListener.removeEvent(gbStream.getApp(), gbStream.getStream()); | |
| 765 | 763 | if (serverId.equals(userSetting.getServerId())) { |
| 766 | 764 | SendRtpItem sendRtpItem = zlmServerFactory.createSendRtpItem(mediaServerItem, addressStr, finalPort, ssrc, requesterId, |
| 767 | 765 | app, stream, channelId, mediaTransmissionTCP, platform.isRtcp()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java
| ... | ... | @@ -13,6 +13,7 @@ import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 13 | 13 | import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; |
| 14 | 14 | import com.genersoft.iot.vmp.service.IDeviceChannelService; |
| 15 | 15 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 16 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 16 | 17 | import org.dom4j.DocumentException; |
| 17 | 18 | import org.dom4j.Element; |
| 18 | 19 | import org.slf4j.Logger; |
| ... | ... | @@ -185,6 +186,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 185 | 186 | // 判断此通道是否存在 |
| 186 | 187 | DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channel.getChannelId()); |
| 187 | 188 | if (deviceChannel != null) { |
| 189 | + logger.info("[增加通道] 已存在,不发送通知只更新,设备: {}, 通道 {}", device.getDeviceId(), channel.getChannelId()); | |
| 188 | 190 | channel.setId(deviceChannel.getId()); |
| 189 | 191 | updateChannelMap.put(channel.getChannelId(), channel); |
| 190 | 192 | if (updateChannelMap.keySet().size() > 300) { |
| ... | ... | @@ -222,6 +224,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 222 | 224 | DeviceChannel deviceChannelForUpdate = deviceChannelService.getOne(deviceId, channel.getChannelId()); |
| 223 | 225 | if (deviceChannelForUpdate != null) { |
| 224 | 226 | channel.setId(deviceChannelForUpdate.getId()); |
| 227 | + channel.setUpdateTime(DateUtil.getNow()); | |
| 225 | 228 | updateChannelMap.put(channel.getChannelId(), channel); |
| 226 | 229 | if (updateChannelMap.keySet().size() > 300) { |
| 227 | 230 | executeSaveForUpdate(); |
| ... | ... | @@ -244,11 +247,11 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 244 | 247 | // 转发变化信息 |
| 245 | 248 | eventPublisher.catalogEventPublish(null, channel, event); |
| 246 | 249 | |
| 247 | - if (updateChannelMap.keySet().size() > 0 | |
| 248 | - || addChannelMap.keySet().size() > 0 | |
| 249 | - || updateChannelOnlineList.size() > 0 | |
| 250 | - || updateChannelOfflineList.size() > 0 | |
| 251 | - || deleteChannelList.size() > 0) { | |
| 250 | + if (!updateChannelMap.keySet().isEmpty() | |
| 251 | + || !addChannelMap.keySet().isEmpty() | |
| 252 | + || !updateChannelOnlineList.isEmpty() | |
| 253 | + || !updateChannelOfflineList.isEmpty() | |
| 254 | + || !deleteChannelList.isEmpty()) { | |
| 252 | 255 | |
| 253 | 256 | if (!dynamicTask.contains(talkKey)) { |
| 254 | 257 | dynamicTask.startDelay(talkKey, this::executeSave, 1000); |
| ... | ... | @@ -262,16 +265,36 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 262 | 265 | } |
| 263 | 266 | |
| 264 | 267 | private void executeSave(){ |
| 265 | - executeSaveForAdd(); | |
| 266 | - executeSaveForUpdate(); | |
| 267 | - executeSaveForDelete(); | |
| 268 | - executeSaveForOnline(); | |
| 269 | - executeSaveForOffline(); | |
| 268 | + try { | |
| 269 | + executeSaveForAdd(); | |
| 270 | + } catch (Exception e) { | |
| 271 | + logger.error("[存储收到的增加通道] 异常: ", e ); | |
| 272 | + } | |
| 273 | + try { | |
| 274 | + executeSaveForUpdate(); | |
| 275 | + } catch (Exception e) { | |
| 276 | + logger.error("[存储收到的更新通道] 异常: ", e ); | |
| 277 | + } | |
| 278 | + try { | |
| 279 | + executeSaveForDelete(); | |
| 280 | + } catch (Exception e) { | |
| 281 | + logger.error("[存储收到的删除通道] 异常: ", e ); | |
| 282 | + } | |
| 283 | + try { | |
| 284 | + executeSaveForOnline(); | |
| 285 | + } catch (Exception e) { | |
| 286 | + logger.error("[存储收到的通道上线] 异常: ", e ); | |
| 287 | + } | |
| 288 | + try { | |
| 289 | + executeSaveForOffline(); | |
| 290 | + } catch (Exception e) { | |
| 291 | + logger.error("[存储收到的通道离线] 异常: ", e ); | |
| 292 | + } | |
| 270 | 293 | dynamicTask.stop(talkKey); |
| 271 | 294 | } |
| 272 | 295 | |
| 273 | 296 | private void executeSaveForUpdate(){ |
| 274 | - if (updateChannelMap.values().size() > 0) { | |
| 297 | + if (!updateChannelMap.values().isEmpty()) { | |
| 275 | 298 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(updateChannelMap.values()); |
| 276 | 299 | updateChannelMap.clear(); |
| 277 | 300 | deviceChannelService.batchUpdateChannel(deviceChannels); |
| ... | ... | @@ -280,7 +303,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 280 | 303 | } |
| 281 | 304 | |
| 282 | 305 | private void executeSaveForAdd(){ |
| 283 | - if (addChannelMap.values().size() > 0) { | |
| 306 | + if (!addChannelMap.values().isEmpty()) { | |
| 284 | 307 | ArrayList<DeviceChannel> deviceChannels = new ArrayList<>(addChannelMap.values()); |
| 285 | 308 | addChannelMap.clear(); |
| 286 | 309 | deviceChannelService.batchAddChannel(deviceChannels); |
| ... | ... | @@ -288,21 +311,21 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent |
| 288 | 311 | } |
| 289 | 312 | |
| 290 | 313 | private void executeSaveForDelete(){ |
| 291 | - if (deleteChannelList.size() > 0) { | |
| 314 | + if (!deleteChannelList.isEmpty()) { | |
| 292 | 315 | deviceChannelService.deleteChannels(deleteChannelList); |
| 293 | 316 | deleteChannelList.clear(); |
| 294 | 317 | } |
| 295 | 318 | } |
| 296 | 319 | |
| 297 | 320 | private void executeSaveForOnline(){ |
| 298 | - if (updateChannelOnlineList.size() > 0) { | |
| 321 | + if (!updateChannelOnlineList.isEmpty()) { | |
| 299 | 322 | deviceChannelService.channelsOnline(updateChannelOnlineList); |
| 300 | 323 | updateChannelOnlineList.clear(); |
| 301 | 324 | } |
| 302 | 325 | } |
| 303 | 326 | |
| 304 | 327 | private void executeSaveForOffline(){ |
| 305 | - if (updateChannelOfflineList.size() > 0) { | |
| 328 | + if (!updateChannelOfflineList.isEmpty()) { | |
| 306 | 329 | deviceChannelService.channelsOffline(updateChannelOfflineList); |
| 307 | 330 | updateChannelOfflineList.clear(); |
| 308 | 331 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java
| ... | ... | @@ -76,7 +76,7 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp |
| 76 | 76 | |
| 77 | 77 | RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); |
| 78 | 78 | if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { |
| 79 | - logger.info("[心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); | |
| 79 | + logger.info("[收到心跳] 设备{}地址变化, 远程地址为: {}:{}", device.getDeviceId(), remoteAddressInfo.getIp(), remoteAddressInfo.getPort()); | |
| 80 | 80 | device.setPort(remoteAddressInfo.getPort()); |
| 81 | 81 | device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); |
| 82 | 82 | device.setIp(remoteAddressInfo.getIp()); | ... | ... |
src/main/java/com/genersoft/iot/vmp/gb28181/utils/XmlUtil.java
| ... | ... | @@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 8 | 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 9 | 9 | import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; |
| 10 | 10 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 11 | +import org.apache.commons.lang3.StringUtils; | |
| 11 | 12 | import org.apache.commons.lang3.math.NumberUtils; |
| 12 | 13 | import org.dom4j.Attribute; |
| 13 | 14 | import org.dom4j.Document; |
| ... | ... | @@ -214,8 +215,11 @@ public class XmlUtil { |
| 214 | 215 | return deviceChannel; |
| 215 | 216 | } |
| 216 | 217 | Element nameElement = itemDevice.element("Name"); |
| 217 | - if (nameElement != null) { | |
| 218 | + // 当通道名称为空时,设置通道名称为通道编码,避免级联时因通道名称为空导致上级接收通道失败 | |
| 219 | + if (nameElement != null && StringUtils.isNotBlank(nameElement.getText())) { | |
| 218 | 220 | deviceChannel.setName(nameElement.getText()); |
| 221 | + } else { | |
| 222 | + deviceChannel.setName(channelId); | |
| 219 | 223 | } |
| 220 | 224 | if(channelId.length() <= 8) { |
| 221 | 225 | deviceChannel.setHasAudio(false); | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/AssistRESTfulUtils.java
| ... | ... | @@ -9,33 +9,58 @@ import org.jetbrains.annotations.NotNull; |
| 9 | 9 | import org.slf4j.Logger; |
| 10 | 10 | import org.slf4j.LoggerFactory; |
| 11 | 11 | import org.springframework.stereotype.Component; |
| 12 | +import org.springframework.util.ObjectUtils; | |
| 12 | 13 | |
| 13 | 14 | import java.io.IOException; |
| 14 | 15 | import java.net.ConnectException; |
| 16 | +import java.net.SocketTimeoutException; | |
| 15 | 17 | import java.util.HashMap; |
| 18 | +import java.util.List; | |
| 16 | 19 | import java.util.Map; |
| 17 | 20 | import java.util.Objects; |
| 21 | +import java.util.concurrent.TimeUnit; | |
| 18 | 22 | |
| 19 | 23 | @Component |
| 20 | 24 | public class AssistRESTfulUtils { |
| 21 | 25 | |
| 22 | 26 | private final static Logger logger = LoggerFactory.getLogger(AssistRESTfulUtils.class); |
| 23 | 27 | |
| 28 | + | |
| 29 | + private OkHttpClient client; | |
| 30 | + | |
| 31 | + | |
| 24 | 32 | public interface RequestCallback{ |
| 25 | 33 | void run(JSONObject response); |
| 26 | 34 | } |
| 27 | 35 | |
| 28 | 36 | private OkHttpClient getClient(){ |
| 29 | - OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); | |
| 30 | - if (logger.isDebugEnabled()) { | |
| 31 | - HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { | |
| 32 | - logger.debug("http请求参数:" + message); | |
| 33 | - }); | |
| 34 | - logging.setLevel(HttpLoggingInterceptor.Level.BASIC); | |
| 35 | - // OkHttp進行添加攔截器loggingInterceptor | |
| 36 | - httpClientBuilder.addInterceptor(logging); | |
| 37 | + return getClient(null); | |
| 38 | + } | |
| 39 | + | |
| 40 | + private OkHttpClient getClient(Integer readTimeOut){ | |
| 41 | + if (client == null) { | |
| 42 | + if (readTimeOut == null) { | |
| 43 | + readTimeOut = 10; | |
| 44 | + } | |
| 45 | + OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder(); | |
| 46 | + // 设置连接超时时间 | |
| 47 | + httpClientBuilder.connectTimeout(8, TimeUnit.SECONDS); | |
| 48 | + // 设置读取超时时间 | |
| 49 | + httpClientBuilder.readTimeout(readTimeOut,TimeUnit.SECONDS); | |
| 50 | + // 设置连接池 | |
| 51 | + httpClientBuilder.connectionPool(new ConnectionPool(16, 5, TimeUnit.MINUTES)); | |
| 52 | + if (logger.isDebugEnabled()) { | |
| 53 | + HttpLoggingInterceptor logging = new HttpLoggingInterceptor(message -> { | |
| 54 | + logger.debug("http请求参数:" + message); | |
| 55 | + }); | |
| 56 | + logging.setLevel(HttpLoggingInterceptor.Level.BASIC); | |
| 57 | + // OkHttp進行添加攔截器loggingInterceptor | |
| 58 | + httpClientBuilder.addInterceptor(logging); | |
| 59 | + } | |
| 60 | + client = httpClientBuilder.build(); | |
| 37 | 61 | } |
| 38 | - return httpClientBuilder.build(); | |
| 62 | + return client; | |
| 63 | + | |
| 39 | 64 | } |
| 40 | 65 | |
| 41 | 66 | |
| ... | ... | @@ -123,13 +148,91 @@ public class AssistRESTfulUtils { |
| 123 | 148 | return responseJSON; |
| 124 | 149 | } |
| 125 | 150 | |
| 151 | + public JSONObject sendPost(MediaServerItem mediaServerItem, String api, JSONObject param, ZLMRESTfulUtils.RequestCallback callback, Integer readTimeOut) { | |
| 152 | + OkHttpClient client = getClient(readTimeOut); | |
| 126 | 153 | |
| 127 | - public JSONObject fileDuration(MediaServerItem mediaServerItem, String app, String stream, RequestCallback callback){ | |
| 128 | - Map<String, Object> param = new HashMap<>(); | |
| 129 | - param.put("app",app); | |
| 130 | - param.put("stream",stream); | |
| 131 | - param.put("recordIng",true); | |
| 132 | - return sendGet(mediaServerItem, "api/record/file/duration",param, callback); | |
| 154 | + if (mediaServerItem == null) { | |
| 155 | + return null; | |
| 156 | + } | |
| 157 | + String url = String.format("http://%s:%s/%s", mediaServerItem.getIp(), mediaServerItem.getRecordAssistPort(), api); | |
| 158 | + JSONObject responseJSON = new JSONObject(); | |
| 159 | + //-2自定义流媒体 调用错误码 | |
| 160 | + responseJSON.put("code",-2); | |
| 161 | + responseJSON.put("msg","ASSIST调用失败"); | |
| 162 | + | |
| 163 | + RequestBody requestBodyJson = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param.toString()); | |
| 164 | + | |
| 165 | + Request request = new Request.Builder() | |
| 166 | + .post(requestBodyJson) | |
| 167 | + .url(url) | |
| 168 | + .addHeader("Content-Type", "application/json") | |
| 169 | + .build(); | |
| 170 | + if (callback == null) { | |
| 171 | + try { | |
| 172 | + Response response = client.newCall(request).execute(); | |
| 173 | + if (response.isSuccessful()) { | |
| 174 | + ResponseBody responseBody = response.body(); | |
| 175 | + if (responseBody != null) { | |
| 176 | + String responseStr = responseBody.string(); | |
| 177 | + responseJSON = JSON.parseObject(responseStr); | |
| 178 | + } | |
| 179 | + }else { | |
| 180 | + response.close(); | |
| 181 | + Objects.requireNonNull(response.body()).close(); | |
| 182 | + } | |
| 183 | + }catch (IOException e) { | |
| 184 | + logger.error(String.format("[ %s ]ASSIST请求失败: %s", url, e.getMessage())); | |
| 185 | + | |
| 186 | + if(e instanceof SocketTimeoutException){ | |
| 187 | + //读取超时超时异常 | |
| 188 | + logger.error(String.format("读取ASSIST数据失败: %s, %s", url, e.getMessage())); | |
| 189 | + } | |
| 190 | + if(e instanceof ConnectException){ | |
| 191 | + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 | |
| 192 | + logger.error(String.format("连接ASSIST失败: %s, %s", url, e.getMessage())); | |
| 193 | + } | |
| 194 | + | |
| 195 | + }catch (Exception e){ | |
| 196 | + logger.error(String.format("访问ASSIST失败: %s, %s", url, e.getMessage())); | |
| 197 | + } | |
| 198 | + }else { | |
| 199 | + client.newCall(request).enqueue(new Callback(){ | |
| 200 | + | |
| 201 | + @Override | |
| 202 | + public void onResponse(@NotNull Call call, @NotNull Response response){ | |
| 203 | + if (response.isSuccessful()) { | |
| 204 | + try { | |
| 205 | + String responseStr = Objects.requireNonNull(response.body()).string(); | |
| 206 | + callback.run(JSON.parseObject(responseStr)); | |
| 207 | + } catch (IOException e) { | |
| 208 | + logger.error(String.format("[ %s ]请求失败: %s", url, e.getMessage())); | |
| 209 | + } | |
| 210 | + | |
| 211 | + }else { | |
| 212 | + response.close(); | |
| 213 | + Objects.requireNonNull(response.body()).close(); | |
| 214 | + } | |
| 215 | + } | |
| 216 | + | |
| 217 | + @Override | |
| 218 | + public void onFailure(@NotNull Call call, @NotNull IOException e) { | |
| 219 | + logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage())); | |
| 220 | + | |
| 221 | + if(e instanceof SocketTimeoutException){ | |
| 222 | + //读取超时超时异常 | |
| 223 | + logger.error(String.format("读取ZLM数据失败: %s, %s", call.request().toString(), e.getMessage())); | |
| 224 | + } | |
| 225 | + if(e instanceof ConnectException){ | |
| 226 | + //判断连接异常,我这里是报Failed to connect to 10.7.5.144 | |
| 227 | + logger.error(String.format("连接ZLM失败: %s, %s", call.request().toString(), e.getMessage())); | |
| 228 | + } | |
| 229 | + } | |
| 230 | + }); | |
| 231 | + } | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + return responseJSON; | |
| 133 | 236 | } |
| 134 | 237 | |
| 135 | 238 | public JSONObject getInfo(MediaServerItem mediaServerItem, RequestCallback callback){ |
| ... | ... | @@ -137,33 +240,41 @@ public class AssistRESTfulUtils { |
| 137 | 240 | return sendGet(mediaServerItem, "api/record/info",param, callback); |
| 138 | 241 | } |
| 139 | 242 | |
| 140 | - public JSONObject addStreamCallInfo(MediaServerItem mediaServerItem, String app, String stream, String callId, RequestCallback callback){ | |
| 141 | - Map<String, Object> param = new HashMap<>(); | |
| 142 | - param.put("app",app); | |
| 143 | - param.put("stream",stream); | |
| 144 | - param.put("callId",callId); | |
| 145 | - return sendGet(mediaServerItem, "api/record/addStreamCallInfo",param, callback); | |
| 146 | - } | |
| 243 | + public JSONObject addTask(MediaServerItem mediaServerItem, String app, String stream, String startTime, | |
| 244 | + String endTime, String callId, List<String> filePathList, String remoteHost) { | |
| 147 | 245 | |
| 148 | - public JSONObject getDateList(MediaServerItem mediaServerItem, String app, String stream, int year, int month) { | |
| 149 | - Map<String, Object> param = new HashMap<>(); | |
| 150 | - param.put("app", app); | |
| 151 | - param.put("stream", stream); | |
| 152 | - param.put("year", year); | |
| 153 | - param.put("month", month); | |
| 154 | - return sendGet(mediaServerItem, "api/record/date/list", param, null); | |
| 246 | + JSONObject videoTaskInfoJSON = new JSONObject(); | |
| 247 | + videoTaskInfoJSON.put("app", app); | |
| 248 | + videoTaskInfoJSON.put("stream", stream); | |
| 249 | + videoTaskInfoJSON.put("startTime", startTime); | |
| 250 | + videoTaskInfoJSON.put("endTime", endTime); | |
| 251 | + videoTaskInfoJSON.put("callId", callId); | |
| 252 | + videoTaskInfoJSON.put("filePathList", filePathList); | |
| 253 | + if (!ObjectUtils.isEmpty(remoteHost)) { | |
| 254 | + videoTaskInfoJSON.put("remoteHost", remoteHost); | |
| 255 | + } | |
| 256 | + | |
| 257 | + return sendPost(mediaServerItem, "api/record/file/download/task/add", videoTaskInfoJSON, null, 30); | |
| 155 | 258 | } |
| 156 | 259 | |
| 157 | - public JSONObject getFileList(MediaServerItem mediaServerItem, int page, int count, String app, String stream, | |
| 158 | - String startTime, String endTime) { | |
| 260 | + public JSONObject queryTaskList(MediaServerItem mediaServerItem, String app, String stream, String callId, String taskId, Boolean isEnd) { | |
| 159 | 261 | Map<String, Object> param = new HashMap<>(); |
| 160 | - param.put("app", app); | |
| 161 | - param.put("stream", stream); | |
| 162 | - param.put("page", page); | |
| 163 | - param.put("count", count); | |
| 164 | - param.put("startTime", startTime); | |
| 165 | - param.put("endTime", endTime); | |
| 166 | - return sendGet(mediaServerItem, "api/record/file/listWithDate", param, null); | |
| 167 | - } | |
| 262 | + if (!ObjectUtils.isEmpty(app)) { | |
| 263 | + param.put("app", app); | |
| 264 | + } | |
| 265 | + if (!ObjectUtils.isEmpty(stream)) { | |
| 266 | + param.put("stream", stream); | |
| 267 | + } | |
| 268 | + if (!ObjectUtils.isEmpty(callId)) { | |
| 269 | + param.put("callId", callId); | |
| 270 | + } | |
| 271 | + if (!ObjectUtils.isEmpty(taskId)) { | |
| 272 | + param.put("taskId", taskId); | |
| 273 | + } | |
| 274 | + if (!ObjectUtils.isEmpty(isEnd)) { | |
| 275 | + param.put("isEnd", isEnd); | |
| 276 | + } | |
| 168 | 277 | |
| 278 | + return sendGet(mediaServerItem, "api/record/file/download/task/list", param, null); | |
| 279 | + } | |
| 169 | 280 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMHttpHookListener.java
| ... | ... | @@ -118,6 +118,9 @@ public class ZLMHttpHookListener { |
| 118 | 118 | private IUserService userService; |
| 119 | 119 | |
| 120 | 120 | @Autowired |
| 121 | + private ICloudRecordService cloudRecordService; | |
| 122 | + | |
| 123 | + @Autowired | |
| 121 | 124 | private VideoStreamSessionManager sessionManager; |
| 122 | 125 | |
| 123 | 126 | @Autowired |
| ... | ... | @@ -238,12 +241,6 @@ public class ZLMHttpHookListener { |
| 238 | 241 | streamAuthorityInfo.setSign(sign); |
| 239 | 242 | // 鉴权通过 |
| 240 | 243 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); |
| 241 | - // 通知assist新的callId | |
| 242 | - if (mediaInfo != null && mediaInfo.getRecordAssistPort() > 0) { | |
| 243 | - taskExecutor.execute(() -> { | |
| 244 | - assistRESTfulUtils.addStreamCallInfo(mediaInfo, param.getApp(), param.getStream(), callId, null); | |
| 245 | - }); | |
| 246 | - } | |
| 247 | 244 | } |
| 248 | 245 | } else { |
| 249 | 246 | zlmMediaListManager.sendStreamEvent(param.getApp(), param.getStream(), param.getMediaServerId()); |
| ... | ... | @@ -251,6 +248,7 @@ public class ZLMHttpHookListener { |
| 251 | 248 | |
| 252 | 249 | |
| 253 | 250 | HookResultForOnPublish result = HookResultForOnPublish.SUCCESS(); |
| 251 | + result.setEnable_audio(true); | |
| 254 | 252 | taskExecutor.execute(() -> { |
| 255 | 253 | ZlmHttpHookSubscribe.Event subscribe = this.subscribe.sendNotify(HookType.on_publish, json); |
| 256 | 254 | if (subscribe != null) { |
| ... | ... | @@ -268,7 +266,6 @@ public class ZLMHttpHookListener { |
| 268 | 266 | } else { |
| 269 | 267 | result.setEnable_mp4(userSetting.isRecordPushLive()); |
| 270 | 268 | } |
| 271 | - | |
| 272 | 269 | // 国标流 |
| 273 | 270 | if ("rtp".equals(param.getApp()) ) { |
| 274 | 271 | |
| ... | ... | @@ -278,14 +275,24 @@ public class ZLMHttpHookListener { |
| 278 | 275 | if (!mediaInfo.isRtpEnable() && inviteInfo == null) { |
| 279 | 276 | String ssrc = String.format("%010d", Long.parseLong(param.getStream(), 16)); |
| 280 | 277 | inviteInfo = inviteStreamService.getInviteInfoBySSRC(ssrc); |
| 281 | - result.setStream_replace(inviteInfo.getStream()); | |
| 282 | - logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | |
| 278 | + if (inviteInfo != null) { | |
| 279 | + result.setStream_replace(inviteInfo.getStream()); | |
| 280 | + logger.info("[ZLM HOOK]推流鉴权 stream: {} 替换为 {}", param.getStream(), inviteInfo.getStream()); | |
| 281 | + } | |
| 283 | 282 | } |
| 284 | 283 | |
| 285 | 284 | // 设置音频信息及录制信息 |
| 286 | - List<SsrcTransaction> ssrcTransactionForAll = (inviteInfo == null ? null : | |
| 287 | - sessionManager.getSsrcTransactionForAll(inviteInfo.getDeviceId(), inviteInfo.getChannelId(), null, null)); | |
| 285 | + List<SsrcTransaction> ssrcTransactionForAll = sessionManager.getSsrcTransactionForAll(null, null, null, param.getStream()); | |
| 288 | 286 | if (ssrcTransactionForAll != null && ssrcTransactionForAll.size() == 1) { |
| 287 | + | |
| 288 | + // 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用 | |
| 289 | + StreamAuthorityInfo streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); | |
| 290 | + streamAuthorityInfo.setApp(param.getApp()); | |
| 291 | + streamAuthorityInfo.setStream(ssrcTransactionForAll.get(0).getStream()); | |
| 292 | + streamAuthorityInfo.setCallId(ssrcTransactionForAll.get(0).getSipTransactionInfo().getCallId()); | |
| 293 | + | |
| 294 | + redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), ssrcTransactionForAll.get(0).getStream(), streamAuthorityInfo); | |
| 295 | + | |
| 289 | 296 | String deviceId = ssrcTransactionForAll.get(0).getDeviceId(); |
| 290 | 297 | String channelId = ssrcTransactionForAll.get(0).getChannelId(); |
| 291 | 298 | DeviceChannel deviceChannel = storager.queryChannel(deviceId, channelId); |
| ... | ... | @@ -294,38 +301,29 @@ public class ZLMHttpHookListener { |
| 294 | 301 | } |
| 295 | 302 | // 如果是录像下载就设置视频间隔十秒 |
| 296 | 303 | if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.DOWNLOAD) { |
| 297 | - result.setMp4_max_second(10); | |
| 298 | - result.setEnable_mp4(true); | |
| 304 | + // 获取录像的总时长,然后设置为这个视频的时长 | |
| 305 | + InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, param.getStream()); | |
| 306 | + if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) { | |
| 307 | + String startTime = inviteInfoForDownload.getStreamInfo().getStartTime(); | |
| 308 | + String endTime = inviteInfoForDownload.getStreamInfo().getEndTime(); | |
| 309 | + long difference = DateUtil.getDifference(startTime, endTime) / 1000; | |
| 310 | + result.setMp4_max_second((int) difference); | |
| 311 | + result.setEnable_mp4(true); | |
| 312 | + // 设置为2保证得到的mp4的时长是正常的 | |
| 313 | + result.setModify_stamp(2); | |
| 314 | + } | |
| 299 | 315 | } |
| 300 | 316 | // 如果是talk对讲,则默认获取声音 |
| 301 | 317 | if (ssrcTransactionForAll.get(0).getType() == InviteSessionType.TALK) { |
| 302 | 318 | result.setEnable_audio(true); |
| 303 | 319 | } |
| 304 | 320 | } |
| 305 | - }else if (param.getApp().equals("broadcast")) { | |
| 321 | + } | |
| 322 | + else if (param.getApp().equals("broadcast")) { | |
| 306 | 323 | result.setEnable_audio(true); |
| 307 | 324 | }else if (param.getApp().equals("talk")) { |
| 308 | 325 | result.setEnable_audio(true); |
| 309 | 326 | } |
| 310 | - | |
| 311 | - if (mediaInfo.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | |
| 312 | - logger.info("推流时发现尚未设置录像路径,从assist服务中读取"); | |
| 313 | - JSONObject info = assistRESTfulUtils.getInfo(mediaInfo, null); | |
| 314 | - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0) { | |
| 315 | - JSONObject dataJson = info.getJSONObject("data"); | |
| 316 | - if (dataJson != null) { | |
| 317 | - String recordPath = dataJson.getString("record"); | |
| 318 | - userSetting.setRecordPath(recordPath); | |
| 319 | - result.setMp4_save_path(recordPath); | |
| 320 | - // 修改zlm中的录像路径 | |
| 321 | - if (mediaInfo.isAutoConfig()) { | |
| 322 | - taskExecutor.execute(() -> { | |
| 323 | - mediaServerService.setZLMConfig(mediaInfo, false); | |
| 324 | - }); | |
| 325 | - } | |
| 326 | - } | |
| 327 | - } | |
| 328 | - } | |
| 329 | 327 | if (param.getApp().equalsIgnoreCase("rtp")) { |
| 330 | 328 | String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + param.getStream(); |
| 331 | 329 | OtherRtpSendInfo otherRtpSendInfo = (OtherRtpSendInfo)redisTemplate.opsForValue().get(receiveKey); |
| ... | ... | @@ -371,13 +369,11 @@ public class ZLMHttpHookListener { |
| 371 | 369 | |
| 372 | 370 | List<OnStreamChangedHookParam.MediaTrack> tracks = param.getTracks(); |
| 373 | 371 | // TODO 重构此处逻辑 |
| 374 | - boolean isPush = false; | |
| 375 | 372 | if (param.isRegist()) { |
| 376 | - // 处理流注册的鉴权信息 | |
| 373 | + // 处理流注册的鉴权信息, 流注销这里不再删除鉴权信息,下次来了新的鉴权信息会对就的进行覆盖 | |
| 377 | 374 | if (param.getOriginType() == OriginType.RTMP_PUSH.ordinal() |
| 378 | 375 | || param.getOriginType() == OriginType.RTSP_PUSH.ordinal() |
| 379 | 376 | || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { |
| 380 | - isPush = true; | |
| 381 | 377 | StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); |
| 382 | 378 | if (streamAuthorityInfo == null) { |
| 383 | 379 | streamAuthorityInfo = StreamAuthorityInfo.getInstanceByHook(param); |
| ... | ... | @@ -387,8 +383,6 @@ public class ZLMHttpHookListener { |
| 387 | 383 | } |
| 388 | 384 | redisCatchStorage.updateStreamAuthorityInfo(param.getApp(), param.getStream(), streamAuthorityInfo); |
| 389 | 385 | } |
| 390 | - } else { | |
| 391 | - redisCatchStorage.removeStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 392 | 386 | } |
| 393 | 387 | |
| 394 | 388 | if ("rtsp".equals(param.getSchema())) { |
| ... | ... | @@ -470,35 +464,40 @@ public class ZLMHttpHookListener { |
| 470 | 464 | } else { |
| 471 | 465 | if (!"rtp".equals(param.getApp())) { |
| 472 | 466 | String type = OriginType.values()[param.getOriginType()].getType(); |
| 473 | - MediaServerItem mediaServerItem = mediaServerService.getOne(param.getMediaServerId()); | |
| 474 | - | |
| 475 | - if (mediaServerItem != null) { | |
| 476 | - if (param.isRegist()) { | |
| 477 | - StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 478 | - String callId = null; | |
| 479 | - if (streamAuthorityInfo != null) { | |
| 480 | - callId = streamAuthorityInfo.getCallId(); | |
| 481 | - } | |
| 482 | - StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaServerItem, | |
| 483 | - param.getApp(), param.getStream(), param.getTracks(), callId); | |
| 484 | - param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | |
| 485 | - redisCatchStorage.addStream(mediaServerItem, type, param.getApp(), param.getStream(), param); | |
| 486 | - if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 487 | - || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 488 | - || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 489 | - param.setSeverId(userSetting.getServerId()); | |
| 490 | - zlmMediaListManager.addPush(param); | |
| 491 | - } | |
| 492 | - } else { | |
| 493 | - // 兼容流注销时类型从redis记录获取 | |
| 494 | - OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | |
| 495 | - param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 496 | - if (onStreamChangedHookParam != null) { | |
| 497 | - type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | |
| 498 | - redisCatchStorage.removeStream(mediaServerItem.getId(), type, param.getApp(), param.getStream()); | |
| 467 | + if (param.isRegist()) { | |
| 468 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo( | |
| 469 | + param.getApp(), param.getStream()); | |
| 470 | + String callId = null; | |
| 471 | + if (streamAuthorityInfo != null) { | |
| 472 | + callId = streamAuthorityInfo.getCallId(); | |
| 473 | + } | |
| 474 | + StreamInfo streamInfoByAppAndStream = mediaService.getStreamInfoByAppAndStream(mediaInfo, | |
| 475 | + param.getApp(), param.getStream(), tracks, callId); | |
| 476 | + param.setStreamInfo(new StreamContent(streamInfoByAppAndStream)); | |
| 477 | + redisCatchStorage.addStream(mediaInfo, type, param.getApp(), param.getStream(), param); | |
| 478 | + if (param.getOriginType() == OriginType.RTSP_PUSH.ordinal() | |
| 479 | + || param.getOriginType() == OriginType.RTMP_PUSH.ordinal() | |
| 480 | + || param.getOriginType() == OriginType.RTC_PUSH.ordinal()) { | |
| 481 | + param.setSeverId(userSetting.getServerId()); | |
| 482 | + zlmMediaListManager.addPush(param); | |
| 483 | + | |
| 484 | + // 冗余数据,自己系统中自用 | |
| 485 | + redisCatchStorage.addPushListItem(param.getApp(), param.getStream(), param); | |
| 486 | + } | |
| 487 | + } else { | |
| 488 | + // 兼容流注销时类型从redis记录获取 | |
| 489 | + OnStreamChangedHookParam onStreamChangedHookParam = redisCatchStorage.getStreamInfo( | |
| 490 | + param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 491 | + if (onStreamChangedHookParam != null) { | |
| 492 | + type = OriginType.values()[onStreamChangedHookParam.getOriginType()].getType(); | |
| 493 | + redisCatchStorage.removeStream(mediaInfo.getId(), type, param.getApp(), param.getStream()); | |
| 494 | + if ("PUSH".equalsIgnoreCase(type)) { | |
| 495 | + // 冗余数据,自己系统中自用 | |
| 496 | + redisCatchStorage.removePushListItem(param.getApp(), param.getStream(), param.getMediaServerId()); | |
| 499 | 497 | } |
| 500 | - GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 501 | - if (gbStream != null) { | |
| 498 | + } | |
| 499 | + GbStream gbStream = storager.getGbStream(param.getApp(), param.getStream()); | |
| 500 | + if (gbStream != null) { | |
| 502 | 501 | // eventPublisher.catalogEventPublishForStream(null, gbStream, CatalogEvent.OFF); |
| 503 | 502 | } |
| 504 | 503 | zlmMediaListManager.removeMedia(param.getApp(), param.getStream()); |
| ... | ... | @@ -618,11 +617,15 @@ public class ZLMHttpHookListener { |
| 618 | 617 | if (info != null) { |
| 619 | 618 | cmder.streamByeCmd(device, inviteInfo.getChannelId(), |
| 620 | 619 | inviteInfo.getStream(), null); |
| 620 | + }else { | |
| 621 | + logger.info("[无人观看] 未找到设备的点播信息: {}, 流:{}", inviteInfo.getDeviceId(), param.getStream()); | |
| 621 | 622 | } |
| 622 | 623 | } catch (InvalidArgumentException | ParseException | SipException | |
| 623 | 624 | SsrcTransactionNotFoundException e) { |
| 624 | 625 | logger.error("[无人观看]点播, 发送BYE失败 {}", e.getMessage()); |
| 625 | 626 | } |
| 627 | + }else { | |
| 628 | + logger.info("[无人观看] 未找到设备: {},流:{}", inviteInfo.getDeviceId(), param.getStream()); | |
| 626 | 629 | } |
| 627 | 630 | |
| 628 | 631 | inviteStreamService.removeInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId(), |
| ... | ... | @@ -858,7 +861,7 @@ public class ZLMHttpHookListener { |
| 858 | 861 | taskExecutor.execute(() -> { |
| 859 | 862 | JSONObject json = (JSONObject) JSON.toJSON(param); |
| 860 | 863 | List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_rtp_server_timeout); |
| 861 | - if (subscribes != null && subscribes.size() > 0) { | |
| 864 | + if (subscribes != null && !subscribes.isEmpty()) { | |
| 862 | 865 | for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { |
| 863 | 866 | subscribe.response(null, param); |
| 864 | 867 | } |
| ... | ... | @@ -868,6 +871,28 @@ public class ZLMHttpHookListener { |
| 868 | 871 | return HookResult.SUCCESS(); |
| 869 | 872 | } |
| 870 | 873 | |
| 874 | + /** | |
| 875 | + * 录像完成事件 | |
| 876 | + */ | |
| 877 | + @ResponseBody | |
| 878 | + @PostMapping(value = "/on_record_mp4", produces = "application/json;charset=UTF-8") | |
| 879 | + public HookResult onRecordMp4(HttpServletRequest request, @RequestBody OnRecordMp4HookParam param) { | |
| 880 | + logger.info("[ZLM HOOK] 录像完成事件:{}->{}", param.getMediaServerId(), param.getFile_path()); | |
| 881 | + | |
| 882 | + taskExecutor.execute(() -> { | |
| 883 | + List<ZlmHttpHookSubscribe.Event> subscribes = this.subscribe.getSubscribes(HookType.on_record_mp4); | |
| 884 | + if (subscribes != null && !subscribes.isEmpty()) { | |
| 885 | + for (ZlmHttpHookSubscribe.Event subscribe : subscribes) { | |
| 886 | + subscribe.response(null, param); | |
| 887 | + } | |
| 888 | + } | |
| 889 | + cloudRecordService.addRecord(param); | |
| 890 | + | |
| 891 | + }); | |
| 892 | + | |
| 893 | + return HookResult.SUCCESS(); | |
| 894 | + } | |
| 895 | + | |
| 871 | 896 | private Map<String, String> urlParamToMap(String params) { |
| 872 | 897 | HashMap<String, String> map = new HashMap<>(); |
| 873 | 898 | if (ObjectUtils.isEmpty(params)) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMRESTfulUtils.java
| ... | ... | @@ -25,8 +25,6 @@ public class ZLMRESTfulUtils { |
| 25 | 25 | |
| 26 | 26 | private OkHttpClient client; |
| 27 | 27 | |
| 28 | - | |
| 29 | - | |
| 30 | 28 | public interface RequestCallback{ |
| 31 | 29 | void run(JSONObject response); |
| 32 | 30 | } |
| ... | ... | @@ -405,4 +403,14 @@ public class ZLMRESTfulUtils { |
| 405 | 403 | param.put("stream_id", streamId); |
| 406 | 404 | return sendPost(mediaServerItem, "updateRtpServerSSRC",param, null); |
| 407 | 405 | } |
| 406 | + | |
| 407 | + public JSONObject deleteRecordDirectory(MediaServerItem mediaServerItem, String app, String stream, String date, String fileName) { | |
| 408 | + Map<String, Object> param = new HashMap<>(1); | |
| 409 | + param.put("vhost", "__defaultVhost__"); | |
| 410 | + param.put("app", app); | |
| 411 | + param.put("stream", stream); | |
| 412 | + param.put("period", date); | |
| 413 | + param.put("name", fileName); | |
| 414 | + return sendPost(mediaServerItem, "deleteRecordDirectory",param, null); | |
| 415 | + } | |
| 408 | 416 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeFactory.java
| ... | ... | @@ -57,4 +57,15 @@ public class HookSubscribeFactory { |
| 57 | 57 | return hookSubscribe; |
| 58 | 58 | } |
| 59 | 59 | |
| 60 | + public static HookSubscribeForRecordMp4 on_record_mp4(String mediaServerId, String app, String stream) { | |
| 61 | + HookSubscribeForRecordMp4 hookSubscribe = new HookSubscribeForRecordMp4(); | |
| 62 | + JSONObject subscribeKey = new com.alibaba.fastjson2.JSONObject(); | |
| 63 | + subscribeKey.put("app", app); | |
| 64 | + subscribeKey.put("stream", stream); | |
| 65 | + subscribeKey.put("mediaServerId", mediaServerId); | |
| 66 | + hookSubscribe.setContent(subscribeKey); | |
| 67 | + | |
| 68 | + return hookSubscribe; | |
| 69 | + } | |
| 70 | + | |
| 60 | 71 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/HookSubscribeForRecordMp4.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSONObject; | |
| 4 | +import com.alibaba.fastjson2.annotation.JSONField; | |
| 5 | + | |
| 6 | +import java.time.Instant; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * hook订阅-录像完成 | |
| 10 | + * @author lin | |
| 11 | + */ | |
| 12 | +public class HookSubscribeForRecordMp4 implements IHookSubscribe{ | |
| 13 | + | |
| 14 | + private HookType hookType = HookType.on_record_mp4; | |
| 15 | + | |
| 16 | + private JSONObject content; | |
| 17 | + | |
| 18 | + @JSONField(format="yyyy-MM-dd HH:mm:ss") | |
| 19 | + private Instant expires; | |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public HookType getHookType() { | |
| 23 | + return hookType; | |
| 24 | + } | |
| 25 | + | |
| 26 | + @Override | |
| 27 | + public JSONObject getContent() { | |
| 28 | + return content; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setContent(JSONObject content) { | |
| 32 | + this.content = content; | |
| 33 | + } | |
| 34 | + | |
| 35 | + @Override | |
| 36 | + public Instant getExpires() { | |
| 37 | + return expires; | |
| 38 | + } | |
| 39 | + | |
| 40 | + @Override | |
| 41 | + public void setExpires(Instant expires) { | |
| 42 | + this.expires = expires; | |
| 43 | + } | |
| 44 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/MediaServerItem.java
| ... | ... | @@ -80,9 +80,11 @@ public class MediaServerItem{ |
| 80 | 80 | @Schema(description = "是否是默认ZLM") |
| 81 | 81 | private boolean defaultServer; |
| 82 | 82 | |
| 83 | - @Schema(description = "当前使用到的端口") | |
| 84 | - private int currentPort; | |
| 83 | + @Schema(description = "录像存储时长") | |
| 84 | + private int recordDay; | |
| 85 | 85 | |
| 86 | + @Schema(description = "录像存储路径") | |
| 87 | + private String recordPath; | |
| 86 | 88 | |
| 87 | 89 | public MediaServerItem() { |
| 88 | 90 | } |
| ... | ... | @@ -269,14 +271,6 @@ public class MediaServerItem{ |
| 269 | 271 | this.updateTime = updateTime; |
| 270 | 272 | } |
| 271 | 273 | |
| 272 | - public int getCurrentPort() { | |
| 273 | - return currentPort; | |
| 274 | - } | |
| 275 | - | |
| 276 | - public void setCurrentPort(int currentPort) { | |
| 277 | - this.currentPort = currentPort; | |
| 278 | - } | |
| 279 | - | |
| 280 | 274 | public boolean isStatus() { |
| 281 | 275 | return status; |
| 282 | 276 | } |
| ... | ... | @@ -308,4 +302,20 @@ public class MediaServerItem{ |
| 308 | 302 | public void setSendRtpPortRange(String sendRtpPortRange) { |
| 309 | 303 | this.sendRtpPortRange = sendRtpPortRange; |
| 310 | 304 | } |
| 305 | + | |
| 306 | + public int getRecordDay() { | |
| 307 | + return recordDay; | |
| 308 | + } | |
| 309 | + | |
| 310 | + public void setRecordDay(int recordDay) { | |
| 311 | + this.recordDay = recordDay; | |
| 312 | + } | |
| 313 | + | |
| 314 | + public String getRecordPath() { | |
| 315 | + return recordPath; | |
| 316 | + } | |
| 317 | + | |
| 318 | + public void setRecordPath(String recordPath) { | |
| 319 | + this.recordPath = recordPath; | |
| 320 | + } | |
| 311 | 321 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java
| ... | ... | @@ -7,6 +7,7 @@ public class HookResultForOnPublish extends HookResult{ |
| 7 | 7 | private int mp4_max_second; |
| 8 | 8 | private String mp4_save_path; |
| 9 | 9 | private String stream_replace; |
| 10 | + private Integer modify_stamp; | |
| 10 | 11 | |
| 11 | 12 | public HookResultForOnPublish() { |
| 12 | 13 | } |
| ... | ... | @@ -60,14 +61,23 @@ public class HookResultForOnPublish extends HookResult{ |
| 60 | 61 | this.stream_replace = stream_replace; |
| 61 | 62 | } |
| 62 | 63 | |
| 64 | + public Integer getModify_stamp() { | |
| 65 | + return modify_stamp; | |
| 66 | + } | |
| 67 | + | |
| 68 | + public void setModify_stamp(Integer modify_stamp) { | |
| 69 | + this.modify_stamp = modify_stamp; | |
| 70 | + } | |
| 71 | + | |
| 63 | 72 | @Override |
| 64 | 73 | public String toString() { |
| 65 | 74 | return "HookResultForOnPublish{" + |
| 66 | 75 | "enable_audio=" + enable_audio + |
| 67 | 76 | ", enable_mp4=" + enable_mp4 + |
| 68 | 77 | ", mp4_max_second=" + mp4_max_second + |
| 69 | - ", stream_replace=" + stream_replace + | |
| 70 | 78 | ", mp4_save_path='" + mp4_save_path + '\'' + |
| 79 | + ", stream_replace='" + stream_replace + '\'' + | |
| 80 | + ", modify_stamp='" + modify_stamp + '\'' + | |
| 71 | 81 | '}'; |
| 72 | 82 | } |
| 73 | 83 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnRecordMp4HookParam.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.media.zlm.dto.hook; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * zlm hook事件中的on_rtp_server_timeout事件的参数 | |
| 5 | + * @author lin | |
| 6 | + */ | |
| 7 | +public class OnRecordMp4HookParam extends HookParam{ | |
| 8 | + private String app; | |
| 9 | + private String stream; | |
| 10 | + private String file_name; | |
| 11 | + private String file_path; | |
| 12 | + private long file_size; | |
| 13 | + private String folder; | |
| 14 | + private String url; | |
| 15 | + private String vhost; | |
| 16 | + private long start_time; | |
| 17 | + private double time_len; | |
| 18 | + | |
| 19 | + public String getApp() { | |
| 20 | + return app; | |
| 21 | + } | |
| 22 | + | |
| 23 | + public void setApp(String app) { | |
| 24 | + this.app = app; | |
| 25 | + } | |
| 26 | + | |
| 27 | + public String getStream() { | |
| 28 | + return stream; | |
| 29 | + } | |
| 30 | + | |
| 31 | + public void setStream(String stream) { | |
| 32 | + this.stream = stream; | |
| 33 | + } | |
| 34 | + | |
| 35 | + public String getFile_name() { | |
| 36 | + return file_name; | |
| 37 | + } | |
| 38 | + | |
| 39 | + public void setFile_name(String file_name) { | |
| 40 | + this.file_name = file_name; | |
| 41 | + } | |
| 42 | + | |
| 43 | + public String getFile_path() { | |
| 44 | + return file_path; | |
| 45 | + } | |
| 46 | + | |
| 47 | + public void setFile_path(String file_path) { | |
| 48 | + this.file_path = file_path; | |
| 49 | + } | |
| 50 | + | |
| 51 | + public long getFile_size() { | |
| 52 | + return file_size; | |
| 53 | + } | |
| 54 | + | |
| 55 | + public void setFile_size(long file_size) { | |
| 56 | + this.file_size = file_size; | |
| 57 | + } | |
| 58 | + | |
| 59 | + public String getFolder() { | |
| 60 | + return folder; | |
| 61 | + } | |
| 62 | + | |
| 63 | + public void setFolder(String folder) { | |
| 64 | + this.folder = folder; | |
| 65 | + } | |
| 66 | + | |
| 67 | + public String getUrl() { | |
| 68 | + return url; | |
| 69 | + } | |
| 70 | + | |
| 71 | + public void setUrl(String url) { | |
| 72 | + this.url = url; | |
| 73 | + } | |
| 74 | + | |
| 75 | + public String getVhost() { | |
| 76 | + return vhost; | |
| 77 | + } | |
| 78 | + | |
| 79 | + public void setVhost(String vhost) { | |
| 80 | + this.vhost = vhost; | |
| 81 | + } | |
| 82 | + | |
| 83 | + public long getStart_time() { | |
| 84 | + return start_time; | |
| 85 | + } | |
| 86 | + | |
| 87 | + public void setStart_time(long start_time) { | |
| 88 | + this.start_time = start_time; | |
| 89 | + } | |
| 90 | + | |
| 91 | + public double getTime_len() { | |
| 92 | + return time_len; | |
| 93 | + } | |
| 94 | + | |
| 95 | + public void setTime_len(double time_len) { | |
| 96 | + this.time_len = time_len; | |
| 97 | + } | |
| 98 | + | |
| 99 | + @Override | |
| 100 | + public String toString() { | |
| 101 | + return "OnRecordMp4HookParam{" + | |
| 102 | + "app='" + app + '\'' + | |
| 103 | + ", stream='" + stream + '\'' + | |
| 104 | + ", file_name='" + file_name + '\'' + | |
| 105 | + ", file_path='" + file_path + '\'' + | |
| 106 | + ", file_size='" + file_size + '\'' + | |
| 107 | + ", folder='" + folder + '\'' + | |
| 108 | + ", url='" + url + '\'' + | |
| 109 | + ", vhost='" + vhost + '\'' + | |
| 110 | + ", start_time=" + start_time + | |
| 111 | + ", time_len=" + time_len + | |
| 112 | + '}'; | |
| 113 | + } | |
| 114 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/ICloudRecordService.java
0 → 100755
| 1 | +package com.genersoft.iot.vmp.service; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSONArray; | |
| 4 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 5 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | |
| 6 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | |
| 7 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 8 | +import com.github.pagehelper.PageInfo; | |
| 9 | + | |
| 10 | +import java.util.List; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * 云端录像管理 | |
| 14 | + * @author lin | |
| 15 | + */ | |
| 16 | +public interface ICloudRecordService { | |
| 17 | + | |
| 18 | + /** | |
| 19 | + * 分页回去云端录像列表 | |
| 20 | + */ | |
| 21 | + PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); | |
| 22 | + | |
| 23 | + /** | |
| 24 | + * 根据hook消息增加一条记录 | |
| 25 | + */ | |
| 26 | + void addRecord(OnRecordMp4HookParam param); | |
| 27 | + | |
| 28 | + /** | |
| 29 | + * 获取所有的日期 | |
| 30 | + */ | |
| 31 | + List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); | |
| 32 | + | |
| 33 | + /** | |
| 34 | + * 添加合并任务 | |
| 35 | + */ | |
| 36 | + String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost); | |
| 37 | + | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 查询合并任务列表 | |
| 41 | + */ | |
| 42 | + JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, Boolean isEnd); | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 收藏视频,收藏的视频过期不会删除 | |
| 46 | + */ | |
| 47 | + int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId); | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 添加指定录像收藏 | |
| 51 | + */ | |
| 52 | + int changeCollectById(Integer recordId, boolean result); | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 获取播放地址 | |
| 56 | + */ | |
| 57 | + DownloadFileInfo getPlayUrlPath(Integer recordId); | |
| 58 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IMediaServerService.java
| ... | ... | @@ -89,21 +89,12 @@ public interface IMediaServerService { |
| 89 | 89 | |
| 90 | 90 | void updateMediaServerKeepalive(String mediaServerId, ServerKeepaliveData data); |
| 91 | 91 | |
| 92 | - boolean checkRtpServer(MediaServerItem mediaServerItem, String rtp, String stream); | |
| 93 | - | |
| 94 | 92 | /** |
| 95 | 93 | * 获取负载信息 |
| 96 | 94 | * @return |
| 97 | 95 | */ |
| 98 | 96 | MediaServerLoad getLoad(MediaServerItem mediaServerItem); |
| 99 | 97 | |
| 100 | - /** | |
| 101 | - * 按时间查找录像文件 | |
| 102 | - */ | |
| 103 | - List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems); | |
| 98 | + List<MediaServerItem> getAllWithAssistPort(); | |
| 104 | 99 | |
| 105 | - /** | |
| 106 | - * 查找存在录像文件的时间 | |
| 107 | - */ | |
| 108 | - List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems); | |
| 109 | 100 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IPlayService.java
| ... | ... | @@ -33,11 +33,6 @@ public interface IPlayService { |
| 33 | 33 | |
| 34 | 34 | MediaServerItem getNewMediaServerItem(Device device); |
| 35 | 35 | |
| 36 | - /** | |
| 37 | - * 获取包含assist服务的节点 | |
| 38 | - */ | |
| 39 | - MediaServerItem getNewMediaServerItemHasAssist(Device device); | |
| 40 | - | |
| 41 | 36 | void playBack(String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); |
| 42 | 37 | void playBack(MediaServerItem mediaServerItem, SSRCInfo ssrcInfo, String deviceId, String channelId, String startTime, String endTime, ErrorCallback<Object> callback); |
| 43 | 38 | void zlmServerOffline(String mediaServerId); |
| ... | ... | @@ -72,5 +67,4 @@ public interface IPlayService { |
| 72 | 67 | |
| 73 | 68 | void getSnap(String deviceId, String channelId, String fileName, ErrorCallback errorCallback); |
| 74 | 69 | |
| 75 | - | |
| 76 | 70 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/IStreamPushService.java
src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.bean; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * 云端录像数据 | |
| 7 | + */ | |
| 8 | +public class CloudRecordItem { | |
| 9 | + /** | |
| 10 | + * 主键 | |
| 11 | + */ | |
| 12 | + private int id; | |
| 13 | + | |
| 14 | + /** | |
| 15 | + * 应用名 | |
| 16 | + */ | |
| 17 | + private String app; | |
| 18 | + | |
| 19 | + /** | |
| 20 | + * 流 | |
| 21 | + */ | |
| 22 | + private String stream; | |
| 23 | + | |
| 24 | + /** | |
| 25 | + * 健全ID | |
| 26 | + */ | |
| 27 | + private String callId; | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 开始时间 | |
| 31 | + */ | |
| 32 | + private long startTime; | |
| 33 | + | |
| 34 | + /** | |
| 35 | + * 结束时间 | |
| 36 | + */ | |
| 37 | + private long endTime; | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * ZLM Id | |
| 41 | + */ | |
| 42 | + private String mediaServerId; | |
| 43 | + | |
| 44 | + /** | |
| 45 | + * 文件名称 | |
| 46 | + */ | |
| 47 | + private String fileName; | |
| 48 | + | |
| 49 | + /** | |
| 50 | + * 文件路径 | |
| 51 | + */ | |
| 52 | + private String filePath; | |
| 53 | + | |
| 54 | + /** | |
| 55 | + * 文件夹 | |
| 56 | + */ | |
| 57 | + private String folder; | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * 收藏,收藏的文件不移除 | |
| 61 | + */ | |
| 62 | + private Boolean collect; | |
| 63 | + | |
| 64 | + /** | |
| 65 | + * 保留,收藏的文件不移除 | |
| 66 | + */ | |
| 67 | + private Boolean reserve; | |
| 68 | + | |
| 69 | + /** | |
| 70 | + * 文件大小 | |
| 71 | + */ | |
| 72 | + private long fileSize; | |
| 73 | + | |
| 74 | + /** | |
| 75 | + * 文件时长 | |
| 76 | + */ | |
| 77 | + private long timeLen; | |
| 78 | + | |
| 79 | + public static CloudRecordItem getInstance(OnRecordMp4HookParam param) { | |
| 80 | + CloudRecordItem cloudRecordItem = new CloudRecordItem(); | |
| 81 | + cloudRecordItem.setApp(param.getApp()); | |
| 82 | + cloudRecordItem.setStream(param.getStream()); | |
| 83 | + cloudRecordItem.setStartTime(param.getStart_time()*1000); | |
| 84 | + cloudRecordItem.setFileName(param.getFile_name()); | |
| 85 | + cloudRecordItem.setFolder(param.getFolder()); | |
| 86 | + cloudRecordItem.setFileSize(param.getFile_size()); | |
| 87 | + cloudRecordItem.setFilePath(param.getFile_path()); | |
| 88 | + cloudRecordItem.setMediaServerId(param.getMediaServerId()); | |
| 89 | + cloudRecordItem.setTimeLen((long) param.getTime_len() * 1000); | |
| 90 | + cloudRecordItem.setEndTime((param.getStart_time() + (long)param.getTime_len()) * 1000); | |
| 91 | + return cloudRecordItem; | |
| 92 | + } | |
| 93 | + | |
| 94 | + public int getId() { | |
| 95 | + return id; | |
| 96 | + } | |
| 97 | + | |
| 98 | + public void setId(int id) { | |
| 99 | + this.id = id; | |
| 100 | + } | |
| 101 | + | |
| 102 | + public String getApp() { | |
| 103 | + return app; | |
| 104 | + } | |
| 105 | + | |
| 106 | + public void setApp(String app) { | |
| 107 | + this.app = app; | |
| 108 | + } | |
| 109 | + | |
| 110 | + public String getStream() { | |
| 111 | + return stream; | |
| 112 | + } | |
| 113 | + | |
| 114 | + public void setStream(String stream) { | |
| 115 | + this.stream = stream; | |
| 116 | + } | |
| 117 | + | |
| 118 | + public String getCallId() { | |
| 119 | + return callId; | |
| 120 | + } | |
| 121 | + | |
| 122 | + public void setCallId(String callId) { | |
| 123 | + this.callId = callId; | |
| 124 | + } | |
| 125 | + | |
| 126 | + public long getStartTime() { | |
| 127 | + return startTime; | |
| 128 | + } | |
| 129 | + | |
| 130 | + public void setStartTime(long startTime) { | |
| 131 | + this.startTime = startTime; | |
| 132 | + } | |
| 133 | + | |
| 134 | + public long getEndTime() { | |
| 135 | + return endTime; | |
| 136 | + } | |
| 137 | + | |
| 138 | + public void setEndTime(long endTime) { | |
| 139 | + this.endTime = endTime; | |
| 140 | + } | |
| 141 | + | |
| 142 | + public String getMediaServerId() { | |
| 143 | + return mediaServerId; | |
| 144 | + } | |
| 145 | + | |
| 146 | + public void setMediaServerId(String mediaServerId) { | |
| 147 | + this.mediaServerId = mediaServerId; | |
| 148 | + } | |
| 149 | + | |
| 150 | + public String getFileName() { | |
| 151 | + return fileName; | |
| 152 | + } | |
| 153 | + | |
| 154 | + public void setFileName(String fileName) { | |
| 155 | + this.fileName = fileName; | |
| 156 | + } | |
| 157 | + | |
| 158 | + public String getFilePath() { | |
| 159 | + return filePath; | |
| 160 | + } | |
| 161 | + | |
| 162 | + public void setFilePath(String filePath) { | |
| 163 | + this.filePath = filePath; | |
| 164 | + } | |
| 165 | + | |
| 166 | + public String getFolder() { | |
| 167 | + return folder; | |
| 168 | + } | |
| 169 | + | |
| 170 | + public void setFolder(String folder) { | |
| 171 | + this.folder = folder; | |
| 172 | + } | |
| 173 | + | |
| 174 | + public long getFileSize() { | |
| 175 | + return fileSize; | |
| 176 | + } | |
| 177 | + | |
| 178 | + public void setFileSize(long fileSize) { | |
| 179 | + this.fileSize = fileSize; | |
| 180 | + } | |
| 181 | + | |
| 182 | + public long getTimeLen() { | |
| 183 | + return timeLen; | |
| 184 | + } | |
| 185 | + | |
| 186 | + public void setTimeLen(long timeLen) { | |
| 187 | + this.timeLen = timeLen; | |
| 188 | + } | |
| 189 | + | |
| 190 | + public Boolean getCollect() { | |
| 191 | + return collect; | |
| 192 | + } | |
| 193 | + | |
| 194 | + public void setCollect(Boolean collect) { | |
| 195 | + this.collect = collect; | |
| 196 | + } | |
| 197 | + | |
| 198 | + public Boolean getReserve() { | |
| 199 | + return reserve; | |
| 200 | + } | |
| 201 | + | |
| 202 | + public void setReserve(Boolean reserve) { | |
| 203 | + this.reserve = reserve; | |
| 204 | + } | |
| 205 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/DownloadFileInfo.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.bean; | |
| 2 | + | |
| 3 | +public class DownloadFileInfo { | |
| 4 | + | |
| 5 | + private String httpPath; | |
| 6 | + private String httpsPath; | |
| 7 | + private String httpDomainPath; | |
| 8 | + private String httpsDomainPath; | |
| 9 | + | |
| 10 | + public String getHttpPath() { | |
| 11 | + return httpPath; | |
| 12 | + } | |
| 13 | + | |
| 14 | + public void setHttpPath(String httpPath) { | |
| 15 | + this.httpPath = httpPath; | |
| 16 | + } | |
| 17 | + | |
| 18 | + public String getHttpsPath() { | |
| 19 | + return httpsPath; | |
| 20 | + } | |
| 21 | + | |
| 22 | + public void setHttpsPath(String httpsPath) { | |
| 23 | + this.httpsPath = httpsPath; | |
| 24 | + } | |
| 25 | + | |
| 26 | + public String getHttpDomainPath() { | |
| 27 | + return httpDomainPath; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public void setHttpDomainPath(String httpDomainPath) { | |
| 31 | + this.httpDomainPath = httpDomainPath; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public String getHttpsDomainPath() { | |
| 35 | + return httpsDomainPath; | |
| 36 | + } | |
| 37 | + | |
| 38 | + public void setHttpsDomainPath(String httpsDomainPath) { | |
| 39 | + this.httpsDomainPath = httpsDomainPath; | |
| 40 | + } | |
| 41 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/bean/WvpRedisMsg.java
| ... | ... | @@ -29,12 +29,12 @@ public class WvpRedisMsg { |
| 29 | 29 | * 消息的ID |
| 30 | 30 | */ |
| 31 | 31 | private String serial; |
| 32 | - private Object content; | |
| 32 | + private String content; | |
| 33 | 33 | |
| 34 | 34 | private final static String requestTag = "req"; |
| 35 | 35 | private final static String responseTag = "res"; |
| 36 | 36 | |
| 37 | - public static WvpRedisMsg getRequestInstance(String fromId, String toId, String cmd, String serial, Object content) { | |
| 37 | + public static WvpRedisMsg getRequestInstance(String fromId, String toId, String cmd, String serial, String content) { | |
| 38 | 38 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); |
| 39 | 39 | wvpRedisMsg.setType(requestTag); |
| 40 | 40 | wvpRedisMsg.setFromId(fromId); |
| ... | ... | @@ -51,7 +51,7 @@ public class WvpRedisMsg { |
| 51 | 51 | return wvpRedisMsg; |
| 52 | 52 | } |
| 53 | 53 | |
| 54 | - public static WvpRedisMsg getResponseInstance(String fromId, String toId, String cmd, String serial, Object content) { | |
| 54 | + public static WvpRedisMsg getResponseInstance(String fromId, String toId, String cmd, String serial, String content) { | |
| 55 | 55 | WvpRedisMsg wvpRedisMsg = new WvpRedisMsg(); |
| 56 | 56 | wvpRedisMsg.setType(responseTag); |
| 57 | 57 | wvpRedisMsg.setFromId(fromId); |
| ... | ... | @@ -106,11 +106,11 @@ public class WvpRedisMsg { |
| 106 | 106 | this.cmd = cmd; |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | - public Object getContent() { | |
| 109 | + public String getContent() { | |
| 110 | 110 | return content; |
| 111 | 111 | } |
| 112 | 112 | |
| 113 | - public void setContent(Object content) { | |
| 113 | + public void setContent(String content) { | |
| 114 | 114 | this.content = content; |
| 115 | 115 | } |
| 116 | 116 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.service.impl; | |
| 2 | + | |
| 3 | +import com.alibaba.fastjson2.JSONArray; | |
| 4 | +import com.alibaba.fastjson2.JSONObject; | |
| 5 | +import com.genersoft.iot.vmp.conf.exception.ControllerException; | |
| 6 | +import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; | |
| 7 | +import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; | |
| 8 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 9 | +import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; | |
| 10 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | |
| 11 | +import com.genersoft.iot.vmp.service.ICloudRecordService; | |
| 12 | +import com.genersoft.iot.vmp.service.IMediaServerService; | |
| 13 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | |
| 14 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 15 | +import com.genersoft.iot.vmp.storager.IRedisCatchStorage; | |
| 16 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | |
| 17 | +import com.genersoft.iot.vmp.utils.CloudRecordUtils; | |
| 18 | +import com.genersoft.iot.vmp.utils.DateUtil; | |
| 19 | +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; | |
| 20 | +import com.github.pagehelper.PageHelper; | |
| 21 | +import com.github.pagehelper.PageInfo; | |
| 22 | +import org.apache.commons.lang3.ObjectUtils; | |
| 23 | +import org.slf4j.Logger; | |
| 24 | +import org.slf4j.LoggerFactory; | |
| 25 | +import org.springframework.beans.factory.annotation.Autowired; | |
| 26 | +import org.springframework.stereotype.Service; | |
| 27 | + | |
| 28 | +import java.time.*; | |
| 29 | +import java.util.*; | |
| 30 | + | |
| 31 | +@Service | |
| 32 | +public class CloudRecordServiceImpl implements ICloudRecordService { | |
| 33 | + | |
| 34 | + private final static Logger logger = LoggerFactory.getLogger(CloudRecordServiceImpl.class); | |
| 35 | + | |
| 36 | + @Autowired | |
| 37 | + private CloudRecordServiceMapper cloudRecordServiceMapper; | |
| 38 | + | |
| 39 | + @Autowired | |
| 40 | + private IMediaServerService mediaServerService; | |
| 41 | + | |
| 42 | + @Autowired | |
| 43 | + private IRedisCatchStorage redisCatchStorage; | |
| 44 | + | |
| 45 | + @Autowired | |
| 46 | + private AssistRESTfulUtils assistRESTfulUtils; | |
| 47 | + | |
| 48 | + @Autowired | |
| 49 | + private VideoStreamSessionManager streamSession; | |
| 50 | + | |
| 51 | + @Override | |
| 52 | + public PageInfo<CloudRecordItem> getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { | |
| 53 | + // 开始时间和结束时间在数据库中都是以秒为单位的 | |
| 54 | + Long startTimeStamp = null; | |
| 55 | + Long endTimeStamp = null; | |
| 56 | + if (startTime != null ) { | |
| 57 | + if (!DateUtil.verification(startTime, DateUtil.formatter)) { | |
| 58 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter); | |
| 59 | + } | |
| 60 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | |
| 61 | + | |
| 62 | + } | |
| 63 | + if (endTime != null ) { | |
| 64 | + if (!DateUtil.verification(endTime, DateUtil.formatter)) { | |
| 65 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter); | |
| 66 | + } | |
| 67 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | |
| 68 | + | |
| 69 | + } | |
| 70 | + PageHelper.startPage(page, count); | |
| 71 | + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(query, app, stream, startTimeStamp, endTimeStamp, | |
| 72 | + null, mediaServerItems); | |
| 73 | + return new PageInfo<>(all); | |
| 74 | + } | |
| 75 | + | |
| 76 | + @Override | |
| 77 | + public List<String> getDateList(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { | |
| 78 | + LocalDate startDate = LocalDate.of(year, month, 1); | |
| 79 | + LocalDate endDate; | |
| 80 | + if (month == 12) { | |
| 81 | + endDate = LocalDate.of(year + 1, 1, 1); | |
| 82 | + }else { | |
| 83 | + endDate = LocalDate.of(year, month + 1, 1); | |
| 84 | + } | |
| 85 | + long startTimeStamp = startDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); | |
| 86 | + long endTimeStamp = endDate.atStartOfDay().toInstant(ZoneOffset.ofHours(8)).getEpochSecond(); | |
| 87 | + List<CloudRecordItem> cloudRecordItemList = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, | |
| 88 | + endTimeStamp, null, mediaServerItems); | |
| 89 | + if (cloudRecordItemList.isEmpty()) { | |
| 90 | + return new ArrayList<>(); | |
| 91 | + } | |
| 92 | + Set<String> resultSet = new HashSet<>(); | |
| 93 | + cloudRecordItemList.stream().forEach(cloudRecordItem -> { | |
| 94 | + String date = DateUtil.timestampTo_yyyy_MM_dd(cloudRecordItem.getStartTime()); | |
| 95 | + resultSet.add(date); | |
| 96 | + }); | |
| 97 | + return new ArrayList<>(resultSet); | |
| 98 | + } | |
| 99 | + | |
| 100 | + @Override | |
| 101 | + public void addRecord(OnRecordMp4HookParam param) { | |
| 102 | + CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(param); | |
| 103 | + StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(param.getApp(), param.getStream()); | |
| 104 | + if (streamAuthorityInfo != null) { | |
| 105 | + cloudRecordItem.setCallId(streamAuthorityInfo.getCallId()); | |
| 106 | + } | |
| 107 | + logger.info("[添加录像记录] {}/{} 文件大小:{}, 时长: {}秒", param.getApp(), param.getStream(), param.getFile_size(),param.getTime_len()); | |
| 108 | + cloudRecordServiceMapper.add(cloudRecordItem); | |
| 109 | + } | |
| 110 | + | |
| 111 | + @Override | |
| 112 | + public String addTask(String app, String stream, String mediaServerId, String startTime, String endTime, String callId, String remoteHost) { | |
| 113 | + // 参数校验 | |
| 114 | + assert app != null; | |
| 115 | + assert stream != null; | |
| 116 | + MediaServerItem mediaServerItem = null; | |
| 117 | + if (mediaServerId == null) { | |
| 118 | + mediaServerItem = mediaServerService.getDefaultMediaServer(); | |
| 119 | + }else { | |
| 120 | + mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 121 | + } | |
| 122 | + if (mediaServerItem == null) { | |
| 123 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体"); | |
| 124 | + }else { | |
| 125 | + if (remoteHost == null) { | |
| 126 | + remoteHost = "http://" + mediaServerItem.getStreamIp() + ":" + mediaServerItem.getRecordAssistPort(); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + if (mediaServerItem.getRecordAssistPort() == 0) { | |
| 130 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "为配置Assist服务"); | |
| 131 | + } | |
| 132 | + Long startTimeStamp = null; | |
| 133 | + Long endTimeStamp = null; | |
| 134 | + if (startTime != null) { | |
| 135 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | |
| 136 | + } | |
| 137 | + if (endTime != null) { | |
| 138 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | |
| 139 | + } | |
| 140 | + | |
| 141 | + List<MediaServerItem> mediaServers = new ArrayList<>(); | |
| 142 | + mediaServers.add(mediaServerItem); | |
| 143 | + // 检索相关的录像文件 | |
| 144 | + List<String> filePathList = cloudRecordServiceMapper.queryRecordFilePathList(app, stream, startTimeStamp, endTimeStamp, callId, mediaServers); | |
| 145 | + if (filePathList == null || filePathList.isEmpty()) { | |
| 146 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未检索到视频文件"); | |
| 147 | + } | |
| 148 | + JSONObject result = assistRESTfulUtils.addTask(mediaServerItem, app, stream, startTime, endTime, callId, filePathList, remoteHost); | |
| 149 | + if (result.getInteger("code") != 0) { | |
| 150 | + throw new ControllerException(result.getInteger("code"), result.getString("msg")); | |
| 151 | + } | |
| 152 | + return result.getString("data"); | |
| 153 | + } | |
| 154 | + | |
| 155 | + @Override | |
| 156 | + public JSONArray queryTask(String app, String stream, String callId, String taskId, String mediaServerId, Boolean isEnd) { | |
| 157 | + MediaServerItem mediaServerItem = null; | |
| 158 | + if (mediaServerId == null) { | |
| 159 | + mediaServerItem = mediaServerService.getDefaultMediaServer(); | |
| 160 | + }else { | |
| 161 | + mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 162 | + } | |
| 163 | + if (mediaServerItem == null) { | |
| 164 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的流媒体"); | |
| 165 | + } | |
| 166 | + JSONObject result = assistRESTfulUtils.queryTaskList(mediaServerItem, app, stream, callId, taskId, isEnd); | |
| 167 | + if (result.getInteger("code") != 0) { | |
| 168 | + throw new ControllerException(result.getInteger("code"), result.getString("msg")); | |
| 169 | + } | |
| 170 | + return result.getJSONArray("data"); | |
| 171 | + } | |
| 172 | + | |
| 173 | + @Override | |
| 174 | + public int changeCollect(boolean result, String app, String stream, String mediaServerId, String startTime, String endTime, String callId) { | |
| 175 | + // 开始时间和结束时间在数据库中都是以秒为单位的 | |
| 176 | + Long startTimeStamp = null; | |
| 177 | + Long endTimeStamp = null; | |
| 178 | + if (startTime != null ) { | |
| 179 | + if (!DateUtil.verification(startTime, DateUtil.formatter)) { | |
| 180 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "开始时间格式错误,正确格式为: " + DateUtil.formatter); | |
| 181 | + } | |
| 182 | + startTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | |
| 183 | + | |
| 184 | + } | |
| 185 | + if (endTime != null ) { | |
| 186 | + if (!DateUtil.verification(endTime, DateUtil.formatter)) { | |
| 187 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "结束时间格式错误,正确格式为: " + DateUtil.formatter); | |
| 188 | + } | |
| 189 | + endTimeStamp = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | |
| 190 | + | |
| 191 | + } | |
| 192 | + | |
| 193 | + List<MediaServerItem> mediaServerItems; | |
| 194 | + if (!ObjectUtils.isEmpty(mediaServerId)) { | |
| 195 | + mediaServerItems = new ArrayList<>(); | |
| 196 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 197 | + if (mediaServerItem == null) { | |
| 198 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到流媒体: " + mediaServerId); | |
| 199 | + } | |
| 200 | + mediaServerItems.add(mediaServerItem); | |
| 201 | + } else { | |
| 202 | + mediaServerItems = null; | |
| 203 | + } | |
| 204 | + | |
| 205 | + List<CloudRecordItem> all = cloudRecordServiceMapper.getList(null, app, stream, startTimeStamp, endTimeStamp, | |
| 206 | + callId, mediaServerItems); | |
| 207 | + if (all.isEmpty()) { | |
| 208 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到待收藏的视频"); | |
| 209 | + } | |
| 210 | + int limitCount = 50; | |
| 211 | + int resultCount = 0; | |
| 212 | + if (all.size() > limitCount) { | |
| 213 | + for (int i = 0; i < all.size(); i += limitCount) { | |
| 214 | + int toIndex = i + limitCount; | |
| 215 | + if (i + limitCount > all.size()) { | |
| 216 | + toIndex = all.size(); | |
| 217 | + } | |
| 218 | + resultCount += cloudRecordServiceMapper.updateCollectList(result, all.subList(i, toIndex)); | |
| 219 | + | |
| 220 | + } | |
| 221 | + }else { | |
| 222 | + resultCount = cloudRecordServiceMapper.updateCollectList(result, all); | |
| 223 | + } | |
| 224 | + return resultCount; | |
| 225 | + } | |
| 226 | + | |
| 227 | + @Override | |
| 228 | + public int changeCollectById(Integer recordId, boolean result) { | |
| 229 | + return cloudRecordServiceMapper.changeCollectById(result, recordId); | |
| 230 | + } | |
| 231 | + | |
| 232 | + @Override | |
| 233 | + public DownloadFileInfo getPlayUrlPath(Integer recordId) { | |
| 234 | + CloudRecordItem recordItem = cloudRecordServiceMapper.queryOne(recordId); | |
| 235 | + if (recordItem == null) { | |
| 236 | + throw new ControllerException(ErrorCode.ERROR400.getCode(), "资源不存在"); | |
| 237 | + } | |
| 238 | + String filePath = recordItem.getFilePath(); | |
| 239 | + MediaServerItem mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId()); | |
| 240 | + return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); | |
| 241 | + } | |
| 242 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/DeviceServiceImpl.java
| ... | ... | @@ -162,6 +162,19 @@ public class DeviceServiceImpl implements IDeviceService { |
| 162 | 162 | sync(device); |
| 163 | 163 | // TODO 如果设备下的通道级联到了其他平台,那么需要发送事件或者notify给上级平台 |
| 164 | 164 | } |
| 165 | + // 上线添加订阅 | |
| 166 | + if (device.getSubscribeCycleForCatalog() > 0) { | |
| 167 | + // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 168 | + addCatalogSubscribe(device); | |
| 169 | + } | |
| 170 | + if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 171 | + addMobilePositionSubscribe(device); | |
| 172 | + } | |
| 173 | + if (userSetting.getDeviceStatusNotify()) { | |
| 174 | + // 发送redis消息 | |
| 175 | + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true); | |
| 176 | + } | |
| 177 | + | |
| 165 | 178 | }else { |
| 166 | 179 | if (deviceChannelMapper.queryAllChannels(device.getDeviceId()).size() == 0) { |
| 167 | 180 | logger.info("[设备上线]: {},通道数为0,查询通道信息", device.getDeviceId()); |
| ... | ... | @@ -174,22 +187,10 @@ public class DeviceServiceImpl implements IDeviceService { |
| 174 | 187 | |
| 175 | 188 | } |
| 176 | 189 | |
| 177 | - // 上线添加订阅 | |
| 178 | - if (device.getSubscribeCycleForCatalog() > 0) { | |
| 179 | - // 查询在线设备那些开启了订阅,为设备开启定时的目录订阅 | |
| 180 | - addCatalogSubscribe(device); | |
| 181 | - } | |
| 182 | - if (device.getSubscribeCycleForMobilePosition() > 0) { | |
| 183 | - addMobilePositionSubscribe(device); | |
| 184 | - } | |
| 185 | 190 | // 刷新过期任务 |
| 186 | 191 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); |
| 187 | 192 | // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 |
| 188 | 193 | dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); |
| 189 | - if (userSetting.getDeviceStatusNotify()) { | |
| 190 | - // 发送redis消息 | |
| 191 | - redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, true); | |
| 192 | - } | |
| 193 | 194 | |
| 194 | 195 | // |
| 195 | 196 | // try { |
| ... | ... | @@ -213,6 +214,13 @@ public class DeviceServiceImpl implements IDeviceService { |
| 213 | 214 | } |
| 214 | 215 | String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; |
| 215 | 216 | dynamicTask.stop(registerExpireTaskKey); |
| 217 | + if (device.isOnLine()) { | |
| 218 | + if (userSetting.getDeviceStatusNotify()) { | |
| 219 | + // 发送redis消息 | |
| 220 | + redisCatchStorage.sendDeviceOrChannelStatus(device.getDeviceId(), null, false); | |
| 221 | + } | |
| 222 | + } | |
| 223 | + | |
| 216 | 224 | device.setOnLine(false); |
| 217 | 225 | redisCatchStorage.updateDevice(device); |
| 218 | 226 | deviceMapper.update(device); |
| ... | ... | @@ -224,7 +232,7 @@ public class DeviceServiceImpl implements IDeviceService { |
| 224 | 232 | for (SsrcTransaction ssrcTransaction : ssrcTransactions) { |
| 225 | 233 | mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); |
| 226 | 234 | mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); |
| 227 | - streamSession.remove(deviceId, ssrcTransaction.getChannelId(), ssrcTransaction.getStream()); | |
| 235 | + streamSession.removeByCallId(deviceId, ssrcTransaction.getChannelId(), ssrcTransaction.getCallId()); | |
| 228 | 236 | } |
| 229 | 237 | } |
| 230 | 238 | // 移除订阅 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/GbStreamServiceImpl.java
| ... | ... | @@ -250,9 +250,6 @@ public class GbStreamServiceImpl implements IGbStreamService { |
| 250 | 250 | if (platform == null) { |
| 251 | 251 | return ; |
| 252 | 252 | } |
| 253 | - if (ObjectUtils.isEmpty(catalogId)) { | |
| 254 | - catalogId = platform.getDeviceGBId(); | |
| 255 | - } | |
| 256 | 253 | if (platformGbStreamMapper.delByPlatformAndCatalogId(platformId, catalogId) > 0) { |
| 257 | 254 | List<GbStream> gbStreams = platformGbStreamMapper.queryChannelInParentPlatformAndCatalog(platformId, catalogId); |
| 258 | 255 | List<DeviceChannel> deviceChannelList = new ArrayList<>(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/InviteStreamServiceImpl.java
| ... | ... | @@ -116,9 +116,12 @@ public class InviteStreamServiceImpl implements IInviteStreamService { |
| 116 | 116 | ":" + (stream != null ? stream : "*") |
| 117 | 117 | + ":*"; |
| 118 | 118 | List<Object> scanResult = RedisUtil.scan(redisTemplate, key); |
| 119 | - if (scanResult.size() != 1) { | |
| 119 | + if (scanResult.isEmpty()) { | |
| 120 | 120 | return null; |
| 121 | 121 | } |
| 122 | + if (scanResult.size() != 1) { | |
| 123 | + logger.warn("[获取InviteInfo] 发现 key: {}存在多条", key); | |
| 124 | + } | |
| 122 | 125 | |
| 123 | 126 | return (InviteInfo) redisTemplate.opsForValue().get(scanResult.get(0)); |
| 124 | 127 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServerServiceImpl.java
| ... | ... | @@ -165,14 +165,13 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 165 | 165 | if (streamId == null) { |
| 166 | 166 | streamId = String.format("%08x", Long.parseLong(ssrc)).toUpperCase(); |
| 167 | 167 | } |
| 168 | - int ssrcCheckParam = 0; | |
| 169 | - if (ssrcCheck && tcpMode > 1) { | |
| 168 | + if (ssrcCheck && tcpMode > 0) { | |
| 170 | 169 | // 目前zlm不支持 tcp模式更新ssrc,暂时关闭ssrc校验 |
| 171 | - logger.warn("[openRTPServer] TCP被动/TCP主动收流时,默认关闭ssrc检验"); | |
| 170 | + logger.warn("[openRTPServer] 平台对接时下级可能自定义ssrc,但是tcp模式zlm收流目前无法更新ssrc,可能收流超时,此时请使用udp收流或者关闭ssrc校验"); | |
| 172 | 171 | } |
| 173 | 172 | int rtpServerPort; |
| 174 | 173 | if (mediaServerItem.isRtpEnable()) { |
| 175 | - rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, (ssrcCheck && tcpMode == 0) ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode); | |
| 174 | + rtpServerPort = zlmServerFactory.createRTPServer(mediaServerItem, streamId, ssrcCheck ? Long.parseLong(ssrc) : 0, port, onlyAuto, reUsePort, tcpMode); | |
| 176 | 175 | } else { |
| 177 | 176 | rtpServerPort = mediaServerItem.getRtpProxyPort(); |
| 178 | 177 | } |
| ... | ... | @@ -205,7 +204,10 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 205 | 204 | @Override |
| 206 | 205 | public void closeRTPServer(String mediaServerId, String streamId) { |
| 207 | 206 | MediaServerItem mediaServerItem = this.getOne(mediaServerId); |
| 208 | - closeRTPServer(mediaServerItem, streamId); | |
| 207 | + if (mediaServerItem.isRtpEnable()) { | |
| 208 | + closeRTPServer(mediaServerItem, streamId); | |
| 209 | + } | |
| 210 | + zlmresTfulUtils.closeStreams(mediaServerItem, "rtp", streamId); | |
| 209 | 211 | } |
| 210 | 212 | |
| 211 | 213 | @Override |
| ... | ... | @@ -428,17 +430,6 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 428 | 430 | |
| 429 | 431 | |
| 430 | 432 | if (serverItem.isAutoConfig()) { |
| 431 | - // 查看assist服务的录像路径配置 | |
| 432 | - if (serverItem.getRecordAssistPort() > 0 && userSetting.getRecordPath() == null) { | |
| 433 | - JSONObject info = assistRESTfulUtils.getInfo(serverItem, null); | |
| 434 | - if (info != null && info.getInteger("code") != null && info.getInteger("code") == 0 ) { | |
| 435 | - JSONObject dataJson = info.getJSONObject("data"); | |
| 436 | - if (dataJson != null) { | |
| 437 | - String recordPath = dataJson.getString("record"); | |
| 438 | - userSetting.setRecordPath(recordPath); | |
| 439 | - } | |
| 440 | - } | |
| 441 | - } | |
| 442 | 433 | setZLMConfig(serverItem, "0".equals(zlmServerConfig.getHookEnable())); |
| 443 | 434 | } |
| 444 | 435 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + serverItem.getId(); |
| ... | ... | @@ -573,7 +564,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 573 | 564 | logger.info("[ZLM] 正在设置 :{} -> {}:{}", |
| 574 | 565 | mediaServerItem.getId(), mediaServerItem.getIp(), mediaServerItem.getHttpPort()); |
| 575 | 566 | String protocol = sslEnabled ? "https" : "http"; |
| 576 | - String hookPrex = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); | |
| 567 | + String hookPrefix = String.format("%s://%s:%s/index/hook", protocol, mediaServerItem.getHookIp(), serverPort); | |
| 577 | 568 | |
| 578 | 569 | Map<String, Object> param = new HashMap<>(); |
| 579 | 570 | param.put("api.secret",mediaServerItem.getSecret()); // -profile:v Baseline |
| ... | ... | @@ -582,25 +573,21 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 582 | 573 | } |
| 583 | 574 | param.put("hook.enable","1"); |
| 584 | 575 | param.put("hook.on_flow_report",""); |
| 585 | - param.put("hook.on_play",String.format("%s/on_play", hookPrex)); | |
| 576 | + param.put("hook.on_play",String.format("%s/on_play", hookPrefix)); | |
| 586 | 577 | param.put("hook.on_http_access",""); |
| 587 | - param.put("hook.on_publish", String.format("%s/on_publish", hookPrex)); | |
| 578 | + param.put("hook.on_publish", String.format("%s/on_publish", hookPrefix)); | |
| 588 | 579 | param.put("hook.on_record_ts",""); |
| 589 | 580 | param.put("hook.on_rtsp_auth",""); |
| 590 | 581 | param.put("hook.on_rtsp_realm",""); |
| 591 | - param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrex)); | |
| 582 | + param.put("hook.on_server_started",String.format("%s/on_server_started", hookPrefix)); | |
| 592 | 583 | param.put("hook.on_shell_login",""); |
| 593 | - param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrex)); | |
| 594 | - param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrex)); | |
| 595 | - param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrex)); | |
| 596 | - param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrex)); | |
| 597 | - param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrex)); | |
| 598 | - param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrex)); | |
| 599 | - if (mediaServerItem.getRecordAssistPort() > 0) { | |
| 600 | - param.put("hook.on_record_mp4",String.format("http://127.0.0.1:%s/api/record/on_record_mp4", mediaServerItem.getRecordAssistPort())); | |
| 601 | - }else { | |
| 602 | - param.put("hook.on_record_mp4",""); | |
| 603 | - } | |
| 584 | + param.put("hook.on_stream_changed",String.format("%s/on_stream_changed", hookPrefix)); | |
| 585 | + param.put("hook.on_stream_none_reader",String.format("%s/on_stream_none_reader", hookPrefix)); | |
| 586 | + param.put("hook.on_stream_not_found",String.format("%s/on_stream_not_found", hookPrefix)); | |
| 587 | + param.put("hook.on_server_keepalive",String.format("%s/on_server_keepalive", hookPrefix)); | |
| 588 | + param.put("hook.on_send_rtp_stopped",String.format("%s/on_send_rtp_stopped", hookPrefix)); | |
| 589 | + param.put("hook.on_rtp_server_timeout",String.format("%s/on_rtp_server_timeout", hookPrefix)); | |
| 590 | + param.put("hook.on_record_mp4",String.format("%s/on_record_mp4", hookPrefix)); | |
| 604 | 591 | param.put("hook.timeoutSec","20"); |
| 605 | 592 | // 推流断开后可以在超时时间内重新连接上继续推流,这样播放器会接着播放。 |
| 606 | 593 | // 置0关闭此特性(推流断开会导致立即断开播放器) |
| ... | ... | @@ -609,15 +596,14 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 609 | 596 | param.put("protocol.continue_push_ms", "3000" ); |
| 610 | 597 | // 最多等待未初始化的Track时间,单位毫秒,超时之后会忽略未初始化的Track, 设置此选项优化那些音频错误的不规范流, |
| 611 | 598 | // 等zlm支持给每个rtpServer设置关闭音频的时候可以不设置此选项 |
| 612 | -// param.put("general.wait_track_ready_ms", "3000" ); | |
| 613 | 599 | if (mediaServerItem.isRtpEnable() && !ObjectUtils.isEmpty(mediaServerItem.getRtpPortRange())) { |
| 614 | 600 | param.put("rtp_proxy.port_range", mediaServerItem.getRtpPortRange().replace(",", "-")); |
| 615 | 601 | } |
| 616 | 602 | |
| 617 | - if (userSetting.getRecordPath() != null) { | |
| 618 | - File recordPathFile = new File(userSetting.getRecordPath()); | |
| 619 | - File mp4SavePathFile = recordPathFile.getParentFile().getAbsoluteFile(); | |
| 620 | - param.put("protocol.mp4_save_path", mp4SavePathFile.getAbsoluteFile()); | |
| 603 | + if (!ObjectUtils.isEmpty(mediaServerItem.getRecordPath())) { | |
| 604 | + File recordPathFile = new File(mediaServerItem.getRecordPath()); | |
| 605 | + param.put("protocol.mp4_save_path", recordPathFile.getParentFile().getPath()); | |
| 606 | + param.put("protocol.downloadRoot", recordPathFile.getParentFile().getPath()); | |
| 621 | 607 | param.put("record.appName", recordPathFile.getName()); |
| 622 | 608 | } |
| 623 | 609 | |
| ... | ... | @@ -722,6 +708,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 722 | 708 | ssrcFactory.initMediaServerSSRC(mediaServerItem.getId(), null); |
| 723 | 709 | String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + "_" + mediaServerItem.getId(); |
| 724 | 710 | redisTemplate.opsForValue().set(key, mediaServerItem); |
| 711 | + resetOnlineServerItem(mediaServerItem); | |
| 725 | 712 | clearRTPServer(mediaServerItem); |
| 726 | 713 | } |
| 727 | 714 | final String zlmKeepaliveKey = zlmKeepaliveKeyPrefix + mediaServerItem.getId(); |
| ... | ... | @@ -750,15 +737,6 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 750 | 737 | } |
| 751 | 738 | |
| 752 | 739 | @Override |
| 753 | - public boolean checkRtpServer(MediaServerItem mediaServerItem, String app, String stream) { | |
| 754 | - JSONObject rtpInfo = zlmresTfulUtils.getRtpInfo(mediaServerItem, stream); | |
| 755 | - if(rtpInfo.getInteger("code") == 0){ | |
| 756 | - return rtpInfo.getBoolean("exist"); | |
| 757 | - } | |
| 758 | - return false; | |
| 759 | - } | |
| 760 | - | |
| 761 | - @Override | |
| 762 | 740 | public MediaServerLoad getLoad(MediaServerItem mediaServerItem) { |
| 763 | 741 | MediaServerLoad result = new MediaServerLoad(); |
| 764 | 742 | result.setId(mediaServerItem.getId()); |
| ... | ... | @@ -771,88 +749,7 @@ public class MediaServerServiceImpl implements IMediaServerService { |
| 771 | 749 | } |
| 772 | 750 | |
| 773 | 751 | @Override |
| 774 | - public List<RecordFile> getRecords(String app, String stream, String startTime, String endTime, List<MediaServerItem> mediaServerItems) { | |
| 775 | - Assert.notNull(app, "app不存在"); | |
| 776 | - Assert.notNull(stream, "stream不存在"); | |
| 777 | - Assert.notNull(startTime, "startTime不存在"); | |
| 778 | - Assert.notNull(endTime, "endTime不存在"); | |
| 779 | - Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | |
| 780 | - | |
| 781 | - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | |
| 782 | - for (int i = 0; i < mediaServerItems.size(); i++) { | |
| 783 | - completableFutures[i] = getRecordFilesForOne(app, stream, startTime, endTime, mediaServerItems.get(i)); | |
| 784 | - } | |
| 785 | - List<RecordFile> result = new ArrayList<>(); | |
| 786 | - for (int i = 0; i < completableFutures.length; i++) { | |
| 787 | - try { | |
| 788 | - List<RecordFile> list = (List<RecordFile>) completableFutures[i].get(); | |
| 789 | - if (!list.isEmpty()) { | |
| 790 | - for (int g = 0; g < list.size(); g++) { | |
| 791 | - list.get(g).setMediaServerId(mediaServerItems.get(i).getId()); | |
| 792 | - } | |
| 793 | - result.addAll(list); | |
| 794 | - } | |
| 795 | - } catch (InterruptedException e) { | |
| 796 | - throw new RuntimeException(e); | |
| 797 | - } catch (ExecutionException e) { | |
| 798 | - throw new RuntimeException(e); | |
| 799 | - } | |
| 800 | - } | |
| 801 | - Comparator<RecordFile> comparator = Comparator.comparing(RecordFile::getFileName); | |
| 802 | - result.sort(comparator); | |
| 803 | - return result; | |
| 804 | - } | |
| 805 | - | |
| 806 | - @Override | |
| 807 | - public List<String> getRecordDates(String app, String stream, int year, int month, List<MediaServerItem> mediaServerItems) { | |
| 808 | - Assert.notNull(app, "app不存在"); | |
| 809 | - Assert.notNull(stream, "stream不存在"); | |
| 810 | - Assert.notEmpty(mediaServerItems, "流媒体列表为空"); | |
| 811 | - CompletableFuture[] completableFutures = new CompletableFuture[mediaServerItems.size()]; | |
| 812 | - | |
| 813 | - for (int i = 0; i < mediaServerItems.size(); i++) { | |
| 814 | - completableFutures[i] = getRecordDatesForOne(app, stream, year, month, mediaServerItems.get(i)); | |
| 815 | - } | |
| 816 | - List<String> result = new ArrayList<>(); | |
| 817 | - CompletableFuture.allOf(completableFutures).join(); | |
| 818 | - for (CompletableFuture completableFuture : completableFutures) { | |
| 819 | - try { | |
| 820 | - List<String> list = (List<String>) completableFuture.get(); | |
| 821 | - result.addAll(list); | |
| 822 | - } catch (InterruptedException e) { | |
| 823 | - throw new RuntimeException(e); | |
| 824 | - } catch (ExecutionException e) { | |
| 825 | - throw new RuntimeException(e); | |
| 826 | - } | |
| 827 | - } | |
| 828 | - Collections.sort(result); | |
| 829 | - return result; | |
| 830 | - } | |
| 831 | - | |
| 832 | - @Async | |
| 833 | - public CompletableFuture<List<String>> getRecordDatesForOne(String app, String stream, int year, int month, MediaServerItem mediaServerItem) { | |
| 834 | - JSONObject fileListJson = assistRESTfulUtils.getDateList(mediaServerItem, app, stream, year, month); | |
| 835 | - if (fileListJson != null && !fileListJson.isEmpty()) { | |
| 836 | - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | |
| 837 | - JSONArray data = fileListJson.getJSONArray("data"); | |
| 838 | - return CompletableFuture.completedFuture(data.toJavaList(String.class)); | |
| 839 | - } | |
| 840 | - } | |
| 841 | - return CompletableFuture.completedFuture(new ArrayList<>()); | |
| 842 | - } | |
| 843 | - | |
| 844 | - @Async | |
| 845 | - public CompletableFuture<List<RecordFile>> getRecordFilesForOne(String app, String stream, String startTime, String endTime, MediaServerItem mediaServerItem) { | |
| 846 | - JSONObject fileListJson = assistRESTfulUtils.getFileList(mediaServerItem, 1, 100000000, app, stream, startTime, endTime); | |
| 847 | - if (fileListJson != null && !fileListJson.isEmpty()) { | |
| 848 | - if (fileListJson.getString("code") != null && fileListJson.getInteger("code") == 0) { | |
| 849 | - JSONObject data = fileListJson.getJSONObject("data"); | |
| 850 | - JSONArray list = data.getJSONArray("list"); | |
| 851 | - if (list != null) { | |
| 852 | - return CompletableFuture.completedFuture(list.toJavaList(RecordFile.class)); | |
| 853 | - } | |
| 854 | - } | |
| 855 | - } | |
| 856 | - return CompletableFuture.completedFuture(new ArrayList<>()); | |
| 752 | + public List<MediaServerItem> getAllWithAssistPort() { | |
| 753 | + return mediaServerMapper.queryAllWithAssistPort(); | |
| 857 | 754 | } |
| 858 | 755 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java
| ... | ... | @@ -64,7 +64,7 @@ public class MediaServiceImpl implements IMediaService { |
| 64 | 64 | if (data == null) { |
| 65 | 65 | return null; |
| 66 | 66 | } |
| 67 | - JSONObject mediaJSON = JSON.parseObject(JSON.toJSONString(data.get(0)), JSONObject.class); | |
| 67 | + JSONObject mediaJSON = data.getJSONObject(0); | |
| 68 | 68 | JSONArray tracks = mediaJSON.getJSONArray("tracks"); |
| 69 | 69 | if (authority) { |
| 70 | 70 | streamInfo = getStreamInfoByAppAndStream(mediaInfo, app, stream, tracks, addr, calld, true); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlatformServiceImpl.java
| ... | ... | @@ -169,7 +169,7 @@ public class PlatformServiceImpl implements IPlatformService { |
| 169 | 169 | dynamicTask.stop(registerTaskKey); |
| 170 | 170 | // 注销旧的 |
| 171 | 171 | try { |
| 172 | - if (parentPlatformOld.isStatus()) { | |
| 172 | + if (parentPlatformOld.isStatus() && parentPlatformCatchOld != null) { | |
| 173 | 173 | logger.info("保存平台{}时发现旧平台在线,发送注销命令", parentPlatformOld.getServerGBId()); |
| 174 | 174 | commanderForPlatform.unregister(parentPlatformOld, parentPlatformCatchOld.getSipTransactionInfo(), null, eventResult -> { |
| 175 | 175 | logger.info("[国标级联] 注销成功, 平台:{}", parentPlatformOld.getServerGBId()); |
| ... | ... | @@ -286,6 +286,7 @@ public class PlatformServiceImpl implements IPlatformService { |
| 286 | 286 | } |
| 287 | 287 | if (parentPlatform.isAutoPushChannel()) { |
| 288 | 288 | if (subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()) == null) { |
| 289 | + logger.info("[国标级联]:{}, 添加自动通道推送模拟订阅信息", parentPlatform.getServerGBId()); | |
| 289 | 290 | addSimulatedSubscribeInfo(parentPlatform); |
| 290 | 291 | } |
| 291 | 292 | }else { |
| ... | ... | @@ -363,9 +364,16 @@ public class PlatformServiceImpl implements IPlatformService { |
| 363 | 364 | // 清除心跳任务 |
| 364 | 365 | dynamicTask.stop(keepaliveTaskKey); |
| 365 | 366 | } |
| 366 | - // 停止目录订阅回复 | |
| 367 | - logger.info("[平台离线] {}, 停止订阅回复", parentPlatform.getServerGBId()); | |
| 368 | - subscribeHolder.removeAllSubscribe(parentPlatform.getServerGBId()); | |
| 367 | + // 停止订阅回复 | |
| 368 | + SubscribeInfo catalogSubscribe = subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()); | |
| 369 | + if (catalogSubscribe != null) { | |
| 370 | + if (catalogSubscribe.getExpires() > 0) { | |
| 371 | + logger.info("[平台离线] {}, 停止目录订阅回复", parentPlatform.getServerGBId()); | |
| 372 | + subscribeHolder.removeCatalogSubscribe(parentPlatform.getServerGBId()); | |
| 373 | + } | |
| 374 | + } | |
| 375 | + logger.info("[平台离线] {}, 停止移动位置订阅回复", parentPlatform.getServerGBId()); | |
| 376 | + subscribeHolder.removeMobilePositionSubscribe(parentPlatform.getServerGBId()); | |
| 369 | 377 | // 发起定时自动重新注册 |
| 370 | 378 | if (!stopRegister) { |
| 371 | 379 | // 设置为60秒自动尝试重新注册 | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/PlayServiceImpl.java
| 1 | 1 | package com.genersoft.iot.vmp.service.impl; |
| 2 | 2 | |
| 3 | +import com.alibaba.fastjson2.JSONArray; | |
| 3 | 4 | import com.alibaba.fastjson2.JSONObject; |
| 4 | 5 | import com.genersoft.iot.vmp.common.InviteInfo; |
| 5 | 6 | import com.genersoft.iot.vmp.common.InviteSessionStatus; |
| ... | ... | @@ -19,13 +20,19 @@ import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| 19 | 20 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; |
| 20 | 21 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 21 | 22 | import com.genersoft.iot.vmp.gb28181.utils.SipUtils; |
| 23 | +import com.genersoft.iot.vmp.media.zlm.ZLMRESTfulUtils; | |
| 24 | +import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; | |
| 25 | +import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 26 | +import com.genersoft.iot.vmp.media.zlm.dto.*; | |
| 22 | 27 | import com.genersoft.iot.vmp.media.zlm.*; |
| 23 | 28 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeFactory; |
| 24 | 29 | import com.genersoft.iot.vmp.media.zlm.dto.HookSubscribeForStreamChange; |
| 25 | 30 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 26 | 31 | import com.genersoft.iot.vmp.media.zlm.dto.hook.HookParam; |
| 32 | +import com.genersoft.iot.vmp.media.zlm.dto.hook.OnRecordMp4HookParam; | |
| 27 | 33 | import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; |
| 28 | 34 | import com.genersoft.iot.vmp.service.*; |
| 35 | +import com.genersoft.iot.vmp.service.bean.*; | |
| 29 | 36 | import com.genersoft.iot.vmp.service.bean.ErrorCallback; |
| 30 | 37 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 31 | 38 | import com.genersoft.iot.vmp.service.bean.RequestPushStreamMsg; |
| ... | ... | @@ -33,6 +40,8 @@ import com.genersoft.iot.vmp.service.bean.SSRCInfo; |
| 33 | 40 | import com.genersoft.iot.vmp.service.redisMsg.RedisGbPlayMsgListener; |
| 34 | 41 | import com.genersoft.iot.vmp.storager.IRedisCatchStorage; |
| 35 | 42 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 43 | +import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; | |
| 44 | +import com.genersoft.iot.vmp.utils.CloudRecordUtils; | |
| 36 | 45 | import com.genersoft.iot.vmp.utils.DateUtil; |
| 37 | 46 | import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; |
| 38 | 47 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| ... | ... | @@ -90,12 +99,18 @@ public class PlayServiceImpl implements IPlayService { |
| 90 | 99 | private IInviteStreamService inviteStreamService; |
| 91 | 100 | |
| 92 | 101 | @Autowired |
| 102 | + private ZlmHttpHookSubscribe subscribe; | |
| 103 | + | |
| 104 | + @Autowired | |
| 93 | 105 | private SendRtpPortManager sendRtpPortManager; |
| 94 | 106 | |
| 95 | 107 | @Autowired |
| 96 | 108 | private ZLMRESTfulUtils zlmresTfulUtils; |
| 97 | 109 | |
| 98 | 110 | @Autowired |
| 111 | + private ZLMServerFactory zlmServerFactory; | |
| 112 | + | |
| 113 | + @Autowired | |
| 99 | 114 | private AssistRESTfulUtils assistRESTfulUtils; |
| 100 | 115 | |
| 101 | 116 | @Autowired |
| ... | ... | @@ -117,7 +132,7 @@ public class PlayServiceImpl implements IPlayService { |
| 117 | 132 | private DynamicTask dynamicTask; |
| 118 | 133 | |
| 119 | 134 | @Autowired |
| 120 | - private ZlmHttpHookSubscribe subscribe; | |
| 135 | + private CloudRecordServiceMapper cloudRecordServiceMapper; | |
| 121 | 136 | |
| 122 | 137 | @Autowired |
| 123 | 138 | private ISIPCommanderForPlatform commanderForPlatform; |
| ... | ... | @@ -407,6 +422,15 @@ public class PlayServiceImpl implements IPlayService { |
| 407 | 422 | HookSubscribeForStreamChange hookSubscribe = HookSubscribeFactory.on_stream_changed("rtp", ssrcInfo.getStream(), true, "rtsp", mediaServerItem.getId()); |
| 408 | 423 | subscribe.removeSubscribe(hookSubscribe); |
| 409 | 424 | } |
| 425 | + }else { | |
| 426 | + logger.info("[点播超时] 收流超时 deviceId: {}, channelId: {},码流类型:{},端口:{}, SSRC: {}", | |
| 427 | + device.getDeviceId(), channelId, device.isSwitchPrimarySubStream() ? "辅码流" : "主码流", | |
| 428 | + ssrcInfo.getPort(), ssrcInfo.getSsrc()); | |
| 429 | + | |
| 430 | + mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); | |
| 431 | + | |
| 432 | + mediaServerService.closeRTPServer(mediaServerItem.getId(), ssrcInfo.getStream()); | |
| 433 | + streamSession.remove(device.getDeviceId(), channelId, ssrcInfo.getStream()); | |
| 410 | 434 | } |
| 411 | 435 | }, userSetting.getPlayTimeout()); |
| 412 | 436 | |
| ... | ... | @@ -437,6 +461,7 @@ public class PlayServiceImpl implements IPlayService { |
| 437 | 461 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 438 | 462 | timeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAY); |
| 439 | 463 | }, (event) -> { |
| 464 | + logger.info("[点播失败] deviceId: {}, channelId:{}, {}: {}", device.getDeviceId(), channelId, event.statusCode, event.msg); | |
| 440 | 465 | dynamicTask.stop(timeOutTaskKey); |
| 441 | 466 | mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); |
| 442 | 467 | // 释放ssrc |
| ... | ... | @@ -478,7 +503,13 @@ public class PlayServiceImpl implements IPlayService { |
| 478 | 503 | if (!device.getStreamMode().equalsIgnoreCase("TCP-ACTIVE")) { |
| 479 | 504 | return; |
| 480 | 505 | } |
| 481 | - String substring = contentString.substring(0, contentString.indexOf("y=")); | |
| 506 | + | |
| 507 | + String substring; | |
| 508 | + if (contentString.indexOf("y=") > 0) { | |
| 509 | + substring = contentString.substring(0, contentString.indexOf("y=")); | |
| 510 | + }else { | |
| 511 | + substring = contentString; | |
| 512 | + } | |
| 482 | 513 | try { |
| 483 | 514 | SessionDescription sdp = SdpFactory.getInstance().createSessionDescription(substring); |
| 484 | 515 | int port = -1; |
| ... | ... | @@ -598,23 +629,6 @@ public class PlayServiceImpl implements IPlayService { |
| 598 | 629 | } |
| 599 | 630 | |
| 600 | 631 | @Override |
| 601 | - public MediaServerItem getNewMediaServerItemHasAssist(Device device) { | |
| 602 | - if (device == null) { | |
| 603 | - return null; | |
| 604 | - } | |
| 605 | - MediaServerItem mediaServerItem; | |
| 606 | - if (ObjectUtils.isEmpty(device.getMediaServerId()) || "auto".equals(device.getMediaServerId())) { | |
| 607 | - mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(true); | |
| 608 | - } else { | |
| 609 | - mediaServerItem = mediaServerService.getOne(device.getMediaServerId()); | |
| 610 | - } | |
| 611 | - if (mediaServerItem == null) { | |
| 612 | - logger.warn("[获取可用的ZLM节点]未找到可使用的ZLM..."); | |
| 613 | - } | |
| 614 | - return mediaServerItem; | |
| 615 | - } | |
| 616 | - | |
| 617 | - @Override | |
| 618 | 632 | public void playBack(String deviceId, String channelId, String startTime, |
| 619 | 633 | String endTime, ErrorCallback<Object> callback) { |
| 620 | 634 | Device device = storager.queryVideoDevice(deviceId); |
| ... | ... | @@ -711,7 +725,6 @@ public class PlayServiceImpl implements IPlayService { |
| 711 | 725 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 |
| 712 | 726 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 713 | 727 | playBackTimeOutTaskKey, callback, inviteInfo, InviteSessionType.PLAYBACK); |
| 714 | - | |
| 715 | 728 | }, errorEvent); |
| 716 | 729 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 717 | 730 | logger.error("[命令发送失败] 录像回放: {}", e.getMessage()); |
| ... | ... | @@ -732,6 +745,10 @@ public class PlayServiceImpl implements IPlayService { |
| 732 | 745 | ResponseEvent responseEvent = (ResponseEvent) eventResult.event; |
| 733 | 746 | String contentString = new String(responseEvent.getResponse().getRawContent()); |
| 734 | 747 | String ssrcInResponse = SipUtils.getSsrcFromSdp(contentString); |
| 748 | + // 兼容回复的消息中缺少ssrc(y字段)的情况 | |
| 749 | + if (ssrcInResponse == null) { | |
| 750 | + ssrcInResponse = ssrcInfo.getSsrc(); | |
| 751 | + } | |
| 735 | 752 | if (ssrcInfo.getSsrc().equals(ssrcInResponse)) { |
| 736 | 753 | // ssrc 一致 |
| 737 | 754 | if (mediaServerItem.isRtpEnable()) { |
| ... | ... | @@ -809,13 +826,15 @@ public class PlayServiceImpl implements IPlayService { |
| 809 | 826 | } |
| 810 | 827 | |
| 811 | 828 | |
| 829 | + | |
| 830 | + | |
| 812 | 831 | @Override |
| 813 | 832 | public void download(String deviceId, String channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback<Object> callback) { |
| 814 | 833 | Device device = storager.queryVideoDevice(deviceId); |
| 815 | 834 | if (device == null) { |
| 816 | 835 | return; |
| 817 | 836 | } |
| 818 | - MediaServerItem newMediaServerItem = getNewMediaServerItemHasAssist(device); | |
| 837 | + MediaServerItem newMediaServerItem = this.getNewMediaServerItem(device); | |
| 819 | 838 | if (newMediaServerItem == null) { |
| 820 | 839 | callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(), |
| 821 | 840 | InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getMsg(), |
| ... | ... | @@ -894,6 +913,28 @@ public class PlayServiceImpl implements IPlayService { |
| 894 | 913 | // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 |
| 895 | 914 | InviteOKHandler(eventResult, ssrcInfo, mediaServerItem, device, channelId, |
| 896 | 915 | downLoadTimeOutTaskKey, callback, inviteInfo, InviteSessionType.DOWNLOAD); |
| 916 | + | |
| 917 | + // 注册录像回调事件,录像下载结束后写入下载地址 | |
| 918 | + ZlmHttpHookSubscribe.Event hookEventForRecord = (mediaServerItemInuse, hookParam) -> { | |
| 919 | + logger.info("[录像下载] 收到录像写入磁盘消息: , {}/{}-{}", | |
| 920 | + inviteInfo.getDeviceId(), inviteInfo.getChannelId(), ssrcInfo.getStream()); | |
| 921 | + logger.info("[录像下载] 收到录像写入磁盘消息内容: " + hookParam); | |
| 922 | + OnRecordMp4HookParam recordMp4HookParam = (OnRecordMp4HookParam)hookParam; | |
| 923 | + String filePath = recordMp4HookParam.getFile_path(); | |
| 924 | + DownloadFileInfo downloadFileInfo = CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); | |
| 925 | + InviteInfo inviteInfoForNew = inviteStreamService.getInviteInfo(inviteInfo.getType(), inviteInfo.getDeviceId() | |
| 926 | + , inviteInfo.getChannelId(), inviteInfo.getStream()); | |
| 927 | + inviteInfoForNew.getStreamInfo().setDownLoadFilePath(downloadFileInfo); | |
| 928 | + inviteStreamService.updateInviteInfo(inviteInfoForNew); | |
| 929 | + }; | |
| 930 | + HookSubscribeForRecordMp4 hookSubscribe = HookSubscribeFactory.on_record_mp4( | |
| 931 | + mediaServerItem.getId(), "rtp", ssrcInfo.getStream()); | |
| 932 | + | |
| 933 | + // 设置过期时间,下载失败时自动处理订阅数据 | |
| 934 | +// long difference = DateUtil.getDifference(startTime, endTime)/1000; | |
| 935 | +// Instant expiresInstant = Instant.now().plusSeconds(TimeUnit.MINUTES.toSeconds(difference * 2)); | |
| 936 | +// hookSubscribe.setExpires(expiresInstant); | |
| 937 | + subscribe.addSubscribe(hookSubscribe, hookEventForRecord); | |
| 897 | 938 | }); |
| 898 | 939 | } catch (InvalidArgumentException | SipException | ParseException e) { |
| 899 | 940 | logger.error("[命令发送失败] 录像下载: {}", e.getMessage()); |
| ... | ... | @@ -909,47 +950,71 @@ public class PlayServiceImpl implements IPlayService { |
| 909 | 950 | @Override |
| 910 | 951 | public StreamInfo getDownLoadInfo(String deviceId, String channelId, String stream) { |
| 911 | 952 | InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, deviceId, channelId, stream); |
| 953 | + if (inviteInfo == null || inviteInfo.getStreamInfo() == null) { | |
| 954 | + logger.warn("[获取下载进度] 未查询到录像下载的信息"); | |
| 955 | + return null; | |
| 956 | + } | |
| 912 | 957 | |
| 913 | - if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { | |
| 914 | - if (inviteInfo.getStreamInfo().getProgress() == 1) { | |
| 915 | - return inviteInfo.getStreamInfo(); | |
| 916 | - } | |
| 958 | + if (inviteInfo.getStreamInfo().getProgress() == 1) { | |
| 959 | + return inviteInfo.getStreamInfo(); | |
| 960 | + } | |
| 917 | 961 | |
| 918 | - // 获取当前已下载时长 | |
| 919 | - String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId(); | |
| 920 | - MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 921 | - if (mediaServerItem == null) { | |
| 922 | - logger.warn("查询录像信息时发现节点已离线"); | |
| 923 | - return null; | |
| 924 | - } | |
| 925 | - if (mediaServerItem.getRecordAssistPort() > 0) { | |
| 926 | - JSONObject jsonObject = assistRESTfulUtils.fileDuration(mediaServerItem, inviteInfo.getStreamInfo().getApp(), inviteInfo.getStreamInfo().getStream(), null); | |
| 927 | - if (jsonObject == null) { | |
| 928 | - throw new ControllerException(ErrorCode.ERROR100.getCode(), "连接Assist服务失败"); | |
| 929 | - } | |
| 930 | - if (jsonObject.getInteger("code") == 0) { | |
| 931 | - long duration = jsonObject.getLong("data"); | |
| 962 | + // 获取当前已下载时长 | |
| 963 | + String mediaServerId = inviteInfo.getStreamInfo().getMediaServerId(); | |
| 964 | + MediaServerItem mediaServerItem = mediaServerService.getOne(mediaServerId); | |
| 965 | + if (mediaServerItem == null) { | |
| 966 | + logger.warn("[获取下载进度] 查询录像信息时发现节点不存在"); | |
| 967 | + return null; | |
| 968 | + } | |
| 969 | + SsrcTransaction ssrcTransaction = streamSession.getSsrcTransaction(deviceId, channelId, null, stream); | |
| 932 | 970 | |
| 933 | - if (duration == 0) { | |
| 934 | - inviteInfo.getStreamInfo().setProgress(0); | |
| 935 | - } else { | |
| 936 | - String startTime = inviteInfo.getStreamInfo().getStartTime(); | |
| 937 | - String endTime = inviteInfo.getStreamInfo().getEndTime(); | |
| 938 | - long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | |
| 939 | - long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | |
| 940 | - | |
| 941 | - BigDecimal currentCount = new BigDecimal(duration / 1000); | |
| 942 | - BigDecimal totalCount = new BigDecimal(end - start); | |
| 943 | - BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); | |
| 944 | - double process = divide.doubleValue(); | |
| 945 | - inviteInfo.getStreamInfo().setProgress(process); | |
| 946 | - } | |
| 947 | - inviteStreamService.updateInviteInfo(inviteInfo); | |
| 948 | - } | |
| 971 | + if (ssrcTransaction == null) { | |
| 972 | + logger.warn("[获取下载进度] 下载已结束"); | |
| 973 | + return null; | |
| 974 | + } | |
| 975 | + | |
| 976 | + JSONObject mediaListJson= zlmresTfulUtils.getMediaList(mediaServerItem, "rtp", stream); | |
| 977 | + if (mediaListJson == null) { | |
| 978 | + logger.warn("[获取下载进度] 从zlm查询进度失败"); | |
| 979 | + return null; | |
| 980 | + } | |
| 981 | + if (mediaListJson.getInteger("code") != 0) { | |
| 982 | + logger.warn("[获取下载进度] 从zlm查询进度出现错误: {}", mediaListJson.getString("msg")); | |
| 983 | + return null; | |
| 984 | + } | |
| 985 | + JSONArray data = mediaListJson.getJSONArray("data"); | |
| 986 | + if (data == null) { | |
| 987 | + logger.warn("[获取下载进度] 从zlm查询进度时未返回数据"); | |
| 988 | + return null; | |
| 989 | + } | |
| 990 | + JSONObject mediaJSON = data.getJSONObject(0); | |
| 991 | + JSONArray tracks = mediaJSON.getJSONArray("tracks"); | |
| 992 | + if (tracks.isEmpty()) { | |
| 993 | + logger.warn("[获取下载进度] 从zlm查询进度时未返回数据"); | |
| 994 | + return null; | |
| 995 | + } | |
| 996 | + JSONObject jsonObject = tracks.getJSONObject(0); | |
| 997 | + long duration = jsonObject.getLongValue("duration"); | |
| 998 | + if (duration == 0) { | |
| 999 | + inviteInfo.getStreamInfo().setProgress(0); | |
| 1000 | + } else { | |
| 1001 | + String startTime = inviteInfo.getStreamInfo().getStartTime(); | |
| 1002 | + String endTime = inviteInfo.getStreamInfo().getEndTime(); | |
| 1003 | + // 此时start和end单位是秒 | |
| 1004 | + long start = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime); | |
| 1005 | + long end = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime); | |
| 1006 | + | |
| 1007 | + BigDecimal currentCount = new BigDecimal(duration); | |
| 1008 | + BigDecimal totalCount = new BigDecimal((end - start) * 1000); | |
| 1009 | + BigDecimal divide = currentCount.divide(totalCount, 2, RoundingMode.HALF_UP); | |
| 1010 | + double process = divide.doubleValue(); | |
| 1011 | + if (process > 0.999) { | |
| 1012 | + process = 1.0; | |
| 949 | 1013 | } |
| 950 | - return inviteInfo.getStreamInfo(); | |
| 1014 | + inviteInfo.getStreamInfo().setProgress(process); | |
| 951 | 1015 | } |
| 952 | - return null; | |
| 1016 | + inviteStreamService.updateInviteInfo(inviteInfo); | |
| 1017 | + return inviteInfo.getStreamInfo(); | |
| 953 | 1018 | } |
| 954 | 1019 | |
| 955 | 1020 | private StreamInfo onPublishHandlerForDownload(MediaServerItem mediaServerItemInuse, HookParam hookParam, String deviceId, String channelId, String startTime, String endTime) { |
| ... | ... | @@ -1219,7 +1284,12 @@ public class PlayServiceImpl implements IPlayService { |
| 1219 | 1284 | throw new ServiceException("mediaServer不存在"); |
| 1220 | 1285 | } |
| 1221 | 1286 | // zlm 暂停RTP超时检查 |
| 1222 | - JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServerItem, streamId); | |
| 1287 | + // 使用zlm中的流ID | |
| 1288 | + String streamKey = inviteInfo.getStream(); | |
| 1289 | + if (!mediaServerItem.isRtpEnable()) { | |
| 1290 | + streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase(); | |
| 1291 | + } | |
| 1292 | + JSONObject jsonObject = zlmresTfulUtils.pauseRtpCheck(mediaServerItem, streamKey); | |
| 1223 | 1293 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { |
| 1224 | 1294 | throw new ServiceException("暂停RTP接收失败"); |
| 1225 | 1295 | } |
| ... | ... | @@ -1242,7 +1312,12 @@ public class PlayServiceImpl implements IPlayService { |
| 1242 | 1312 | throw new ServiceException("mediaServer不存在"); |
| 1243 | 1313 | } |
| 1244 | 1314 | // zlm 暂停RTP超时检查 |
| 1245 | - JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServerItem, streamId); | |
| 1315 | + // 使用zlm中的流ID | |
| 1316 | + String streamKey = inviteInfo.getStream(); | |
| 1317 | + if (!mediaServerItem.isRtpEnable()) { | |
| 1318 | + streamKey = Long.toHexString(Long.parseLong(inviteInfo.getSsrcInfo().getSsrc())).toUpperCase(); | |
| 1319 | + } | |
| 1320 | + JSONObject jsonObject = zlmresTfulUtils.resumeRtpCheck(mediaServerItem, streamKey); | |
| 1246 | 1321 | if (jsonObject == null || jsonObject.getInteger("code") != 0) { |
| 1247 | 1322 | throw new ServiceException("继续RTP接收失败"); |
| 1248 | 1323 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamProxyServiceImpl.java
| ... | ... | @@ -126,7 +126,13 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 126 | 126 | } |
| 127 | 127 | JSONArray dataArray = jsonObject.getJSONArray("data"); |
| 128 | 128 | JSONObject mediaServerConfig = dataArray.getJSONObject(0); |
| 129 | + if (ObjectUtils.isEmpty(param.getFfmpegCmdKey())) { | |
| 130 | + param.setFfmpegCmdKey("ffmpeg.cmd"); | |
| 131 | + } | |
| 129 | 132 | String ffmpegCmd = mediaServerConfig.getString(param.getFfmpegCmdKey()); |
| 133 | + if (ffmpegCmd == null) { | |
| 134 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法获取ffmpeg cmd"); | |
| 135 | + } | |
| 130 | 136 | String schema = getSchemaFromFFmpegCmd(ffmpegCmd); |
| 131 | 137 | if (schema == null) { |
| 132 | 138 | throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理无法从ffmpeg cmd中获取到输出格式"); |
| ... | ... | @@ -401,6 +407,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 401 | 407 | logger.info("启用代理失败: {}/{}->{}({})", app, stream, jsonObject.getString("msg"), |
| 402 | 408 | streamProxy.getSrcUrl() == null? streamProxy.getUrl():streamProxy.getSrcUrl()); |
| 403 | 409 | } |
| 410 | + } else if (streamProxy != null && streamProxy.isEnable()) { | |
| 411 | + return true ; | |
| 404 | 412 | } |
| 405 | 413 | return result; |
| 406 | 414 | } |
| ... | ... | @@ -452,7 +460,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { |
| 452 | 460 | streamProxyMapper.deleteAutoRemoveItemByMediaServerId(mediaServerId); |
| 453 | 461 | |
| 454 | 462 | // 移除拉流代理生成的流信息 |
| 455 | -// syncPullStream(mediaServerId); | |
| 463 | + syncPullStream(mediaServerId); | |
| 456 | 464 | |
| 457 | 465 | // 恢复流代理, 只查找这个这个流媒体 |
| 458 | 466 | List<StreamProxyItem> streamProxyListForEnable = storager.getStreamProxyListForEnableInMediaServer( | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/impl/StreamPushServiceImpl.java
| ... | ... | @@ -282,6 +282,8 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 282 | 282 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); |
| 283 | 283 | // 移除redis内流的信息 |
| 284 | 284 | redisCatchStorage.removeStream(mediaServerItem.getId(), "PUSH", offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream()); |
| 285 | + // 冗余数据,自己系统中自用 | |
| 286 | + redisCatchStorage.removePushListItem(offlineOnStreamChangedHookParam.getApp(), offlineOnStreamChangedHookParam.getStream(), mediaServerItem.getId()); | |
| 285 | 287 | } |
| 286 | 288 | } |
| 287 | 289 | |
| ... | ... | @@ -319,6 +321,9 @@ public class StreamPushServiceImpl implements IStreamPushService { |
| 319 | 321 | jsonObject.put("register", false); |
| 320 | 322 | jsonObject.put("mediaServerId", mediaServerId); |
| 321 | 323 | redisCatchStorage.sendStreamChangeMsg(type, jsonObject); |
| 324 | + | |
| 325 | + // 冗余数据,自己系统中自用 | |
| 326 | + redisCatchStorage.removePushListItem(onStreamChangedHookParam.getApp(), onStreamChangedHookParam.getStream(), mediaServerId); | |
| 322 | 327 | } |
| 323 | 328 | } |
| 324 | 329 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGbPlayMsgListener.java
| ... | ... | @@ -113,8 +113,8 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 113 | 113 | while (!taskQueue.isEmpty()) { |
| 114 | 114 | Message msg = taskQueue.poll(); |
| 115 | 115 | try { |
| 116 | - JSONObject msgJSON = JSON.parseObject(msg.getBody(), JSONObject.class); | |
| 117 | - WvpRedisMsg wvpRedisMsg = JSON.to(WvpRedisMsg.class, msgJSON); | |
| 116 | + WvpRedisMsg wvpRedisMsg = JSON.parseObject(msg.getBody(), WvpRedisMsg.class); | |
| 117 | + logger.info("[收到REDIS通知] 消息: {}", JSON.toJSONString(wvpRedisMsg)); | |
| 118 | 118 | if (!userSetting.getServerId().equals(wvpRedisMsg.getToId())) { |
| 119 | 119 | continue; |
| 120 | 120 | } |
| ... | ... | @@ -123,7 +123,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 123 | 123 | |
| 124 | 124 | switch (wvpRedisMsg.getCmd()){ |
| 125 | 125 | case WvpRedisMsgCmd.GET_SEND_ITEM: |
| 126 | - RequestSendItemMsg content = JSON.to(RequestSendItemMsg.class, wvpRedisMsg.getContent()); | |
| 126 | + RequestSendItemMsg content = JSON.parseObject(wvpRedisMsg.getContent(), RequestSendItemMsg.class); | |
| 127 | 127 | requestSendItemMsgHand(content, wvpRedisMsg.getFromId(), wvpRedisMsg.getSerial()); |
| 128 | 128 | break; |
| 129 | 129 | case WvpRedisMsgCmd.REQUEST_PUSH_STREAM: |
| ... | ... | @@ -242,7 +242,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 242 | 242 | result.setData(content); |
| 243 | 243 | |
| 244 | 244 | WvpRedisMsg response = WvpRedisMsg.getResponseInstance(userSetting.getServerId(), toId, |
| 245 | - WvpRedisMsgCmd.REQUEST_PUSH_STREAM, serial, result); | |
| 245 | + WvpRedisMsgCmd.REQUEST_PUSH_STREAM, serial, JSON.toJSONString(result)); | |
| 246 | 246 | JSONObject jsonObject = (JSONObject)JSON.toJSON(response); |
| 247 | 247 | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| 248 | 248 | } |
| ... | ... | @@ -260,7 +260,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 260 | 260 | result.setMsg("流媒体不存在"); |
| 261 | 261 | |
| 262 | 262 | WvpRedisMsg response = WvpRedisMsg.getResponseInstance(userSetting.getServerId(), toId, |
| 263 | - WvpRedisMsgCmd.GET_SEND_ITEM, serial, result); | |
| 263 | + WvpRedisMsgCmd.GET_SEND_ITEM, serial, JSON.toJSONString(result)); | |
| 264 | 264 | |
| 265 | 265 | JSONObject jsonObject = (JSONObject)JSON.toJSON(response); |
| 266 | 266 | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| ... | ... | @@ -283,7 +283,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 283 | 283 | WVPResult<SendRtpItem> result = new WVPResult<>(); |
| 284 | 284 | result.setCode(ERROR_CODE_TIMEOUT); |
| 285 | 285 | WvpRedisMsg response = WvpRedisMsg.getResponseInstance( |
| 286 | - userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, result | |
| 286 | + userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, JSON.toJSONString(result) | |
| 287 | 287 | ); |
| 288 | 288 | JSONObject jsonObject = (JSONObject)JSON.toJSON(response); |
| 289 | 289 | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| ... | ... | @@ -324,7 +324,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 324 | 324 | result.setData(responseSendItemMsg); |
| 325 | 325 | |
| 326 | 326 | WvpRedisMsg response = WvpRedisMsg.getResponseInstance( |
| 327 | - userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, result | |
| 327 | + userSetting.getServerId(), toId, WvpRedisMsgCmd.GET_SEND_ITEM, serial, JSON.toJSONString(result) | |
| 328 | 328 | ); |
| 329 | 329 | JSONObject jsonObject = (JSONObject)JSON.toJSON(response); |
| 330 | 330 | redisTemplate.convertAndSend(WVP_PUSH_STREAM_KEY, jsonObject); |
| ... | ... | @@ -350,7 +350,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 350 | 350 | requestSendItemMsg.setServerId(serverId); |
| 351 | 351 | String key = UUID.randomUUID().toString(); |
| 352 | 352 | WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId, WvpRedisMsgCmd.GET_SEND_ITEM, |
| 353 | - key, requestSendItemMsg); | |
| 353 | + key, JSON.toJSONString(requestSendItemMsg)); | |
| 354 | 354 | |
| 355 | 355 | JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg); |
| 356 | 356 | logger.info("[请求推流SendItem] {}: {}", serverId, jsonObject); |
| ... | ... | @@ -375,7 +375,7 @@ public class RedisGbPlayMsgListener implements MessageListener { |
| 375 | 375 | public void sendMsgForStartSendRtpStream(String serverId, RequestPushStreamMsg param, PlayMsgCallbackForStartSendRtpStream callback) { |
| 376 | 376 | String key = UUID.randomUUID().toString(); |
| 377 | 377 | WvpRedisMsg redisMsg = WvpRedisMsg.getRequestInstance(userSetting.getServerId(), serverId, |
| 378 | - WvpRedisMsgCmd.REQUEST_PUSH_STREAM, key, param); | |
| 378 | + WvpRedisMsgCmd.REQUEST_PUSH_STREAM, key, JSON.toJSONString(param)); | |
| 379 | 379 | |
| 380 | 380 | JSONObject jsonObject = (JSONObject)JSON.toJSON(redisMsg); |
| 381 | 381 | logger.info("[REDIS 请求其他平台推流] {}: {}", serverId, jsonObject); | ... | ... |
src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisGpsMsgListener.java
| ... | ... | @@ -50,11 +50,12 @@ public class RedisGpsMsgListener implements MessageListener { |
| 50 | 50 | Message msg = taskQueue.poll(); |
| 51 | 51 | try { |
| 52 | 52 | GPSMsgInfo gpsMsgInfo = JSON.parseObject(msg.getBody(), GPSMsgInfo.class); |
| 53 | + logger.info("[REDIS的位置变化通知], {}", JSON.toJSONString(gpsMsgInfo)); | |
| 53 | 54 | // 只是放入redis缓存起来 |
| 54 | 55 | redisCatchStorage.updateGpsMsgInfo(gpsMsgInfo); |
| 55 | 56 | }catch (Exception e) { |
| 56 | - logger.warn("[REDIS的ALARM通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); | |
| 57 | - logger.error("[REDIS的ALARM通知] 异常内容: ", e); | |
| 57 | + logger.warn("[REDIS的位置变化通知] 发现未处理的异常, \r\n{}", JSON.toJSONString(message)); | |
| 58 | + logger.error("[REDIS的位置变化通知] 异常内容: ", e); | |
| 58 | 59 | } |
| 59 | 60 | } |
| 60 | 61 | }); | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java
| ... | ... | @@ -208,4 +208,8 @@ public interface IRedisCatchStorage { |
| 208 | 208 | void sendPlatformStartPlayMsg(MessageForPushChannel messageForPushChannel); |
| 209 | 209 | |
| 210 | 210 | void sendPlatformStopPlayMsg(MessageForPushChannel messageForPushChannel); |
| 211 | + | |
| 212 | + void addPushListItem(String app, String stream, OnStreamChangedHookParam param); | |
| 213 | + | |
| 214 | + void removePushListItem(String app, String stream, String mediaServerId); | |
| 211 | 215 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.storager.dao; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 4 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | |
| 5 | +import org.apache.ibatis.annotations.*; | |
| 6 | + | |
| 7 | +import java.util.List; | |
| 8 | + | |
| 9 | +@Mapper | |
| 10 | +public interface CloudRecordServiceMapper { | |
| 11 | + | |
| 12 | + @Insert(" <script>" + | |
| 13 | + "INSERT INTO wvp_cloud_record (" + | |
| 14 | + " app," + | |
| 15 | + " stream," + | |
| 16 | + "<if test=\"callId != null\"> call_id,</if>" + | |
| 17 | + " start_time," + | |
| 18 | + " end_time," + | |
| 19 | + " media_server_id," + | |
| 20 | + " file_name," + | |
| 21 | + " folder," + | |
| 22 | + " file_path," + | |
| 23 | + " file_size," + | |
| 24 | + " time_len ) " + | |
| 25 | + "VALUES (" + | |
| 26 | + " #{app}," + | |
| 27 | + " #{stream}," + | |
| 28 | + " <if test=\"callId != null\"> #{callId},</if>" + | |
| 29 | + " #{startTime}," + | |
| 30 | + " #{endTime}," + | |
| 31 | + " #{mediaServerId}," + | |
| 32 | + " #{fileName}," + | |
| 33 | + " #{folder}," + | |
| 34 | + " #{filePath}," + | |
| 35 | + " #{fileSize}," + | |
| 36 | + " #{timeLen})" + | |
| 37 | + " </script>") | |
| 38 | + int add(CloudRecordItem cloudRecordItem); | |
| 39 | + | |
| 40 | + @Select(" <script>" + | |
| 41 | + "select * " + | |
| 42 | + " from wvp_cloud_record " + | |
| 43 | + " where 0 = 0" + | |
| 44 | + " <if test='query != null'> AND (app LIKE concat('%',#{query},'%') OR stream LIKE concat('%',#{query},'%') )</if> " + | |
| 45 | + " <if test= 'app != null '> and app=#{app}</if>" + | |
| 46 | + " <if test= 'stream != null '> and stream=#{stream}</if>" + | |
| 47 | + " <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" + | |
| 48 | + " <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" + | |
| 49 | + " <if test= 'callId != null '> and call_id = #{callId}</if>" + | |
| 50 | + " <if test= 'mediaServerItemList != null ' > and media_server_id in " + | |
| 51 | + " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + | |
| 52 | + " </if>" + | |
| 53 | + " order by start_time DESC" + | |
| 54 | + | |
| 55 | + " </script>") | |
| 56 | + List<CloudRecordItem> getList(@Param("query") String query, @Param("app") String app, @Param("stream") String stream, | |
| 57 | + @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, | |
| 58 | + @Param("callId")String callId, List<MediaServerItem> mediaServerItemList); | |
| 59 | + | |
| 60 | + | |
| 61 | + @Select(" <script>" + | |
| 62 | + "select file_path" + | |
| 63 | + " from wvp_cloud_record " + | |
| 64 | + " where 0 = 0" + | |
| 65 | + " <if test= 'app != null '> and app=#{app}</if>" + | |
| 66 | + " <if test= 'stream != null '> and stream=#{stream}</if>" + | |
| 67 | + " <if test= 'startTimeStamp != null '> and end_time >= #{startTimeStamp}</if>" + | |
| 68 | + " <if test= 'endTimeStamp != null '> and start_time <= #{endTimeStamp}</if>" + | |
| 69 | + " <if test= 'callId != null '> and call_id = #{callId}</if>" + | |
| 70 | + " <if test= 'mediaServerItemList != null ' > and media_server_id in " + | |
| 71 | + " <foreach collection='mediaServerItemList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + | |
| 72 | + " </if>" + | |
| 73 | + " </script>") | |
| 74 | + List<String> queryRecordFilePathList(@Param("app") String app, @Param("stream") String stream, | |
| 75 | + @Param("startTimeStamp")Long startTimeStamp, @Param("endTimeStamp")Long endTimeStamp, | |
| 76 | + @Param("callId")String callId, List<MediaServerItem> mediaServerItemList); | |
| 77 | + | |
| 78 | + @Update(" <script>" + | |
| 79 | + "update wvp_cloud_record set collect = #{collect} where file_path in " + | |
| 80 | + " <foreach collection='cloudRecordItemList' item='item' open='(' separator=',' close=')' > #{item.filePath}</foreach>" + | |
| 81 | + " </script>") | |
| 82 | + int updateCollectList(@Param("collect") boolean collect, List<CloudRecordItem> cloudRecordItemList); | |
| 83 | + | |
| 84 | + @Delete(" <script>" + | |
| 85 | + "delete from wvp_cloud_record where media_server_id=#{mediaServerId} and file_path in " + | |
| 86 | + " <foreach collection='filePathList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" + | |
| 87 | + " </script>") | |
| 88 | + void deleteByFileList(List<String> filePathList, @Param("mediaServerId") String mediaServerId); | |
| 89 | + | |
| 90 | + | |
| 91 | + @Select(" <script>" + | |
| 92 | + "select *" + | |
| 93 | + " from wvp_cloud_record " + | |
| 94 | + " where collect = false and end_time <= #{endTimeStamp} and media_server_id = #{mediaServerId} " + | |
| 95 | + " </script>") | |
| 96 | + List<CloudRecordItem> queryRecordListForDelete(@Param("endTimeStamp")Long endTimeStamp, String mediaServerId); | |
| 97 | + | |
| 98 | + @Update(" <script>" + | |
| 99 | + "update wvp_cloud_record set collect = #{collect} where id = #{recordId} " + | |
| 100 | + " </script>") | |
| 101 | + int changeCollectById(@Param("collect") boolean collect, @Param("recordId") Integer recordId); | |
| 102 | + | |
| 103 | + @Delete(" <script>" + | |
| 104 | + "delete from wvp_cloud_record where id in " + | |
| 105 | + " <foreach collection='cloudRecordItemIdList' item='item' open='(' separator=',' close=')' > #{item.id}</foreach>" + | |
| 106 | + " </script>") | |
| 107 | + int deleteList(List<CloudRecordItem> cloudRecordItemIdList); | |
| 108 | + | |
| 109 | + @Select(" <script>" + | |
| 110 | + "select *" + | |
| 111 | + " from wvp_cloud_record " + | |
| 112 | + "where call_id = #{callId}" + | |
| 113 | + " </script>") | |
| 114 | + List<CloudRecordItem> getListByCallId(@Param("callId") String callId); | |
| 115 | + | |
| 116 | + @Select(" <script>" + | |
| 117 | + "select *" + | |
| 118 | + " from wvp_cloud_record " + | |
| 119 | + "where id = #{id}" + | |
| 120 | + " </script>") | |
| 121 | + CloudRecordItem queryOne(@Param("id") Integer id); | |
| 122 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceChannelMapper.java
| ... | ... | @@ -6,7 +6,6 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannelInPlatform; |
| 6 | 6 | import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.ChannelReduce; |
| 7 | 7 | import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; |
| 8 | 8 | import org.apache.ibatis.annotations.*; |
| 9 | -import org.apache.ibatis.annotations.Param; | |
| 10 | 9 | import org.springframework.stereotype.Repository; |
| 11 | 10 | |
| 12 | 11 | import java.util.List; |
| ... | ... | @@ -31,7 +30,7 @@ public interface DeviceChannelMapper { |
| 31 | 30 | @Update(value = {" <script>" + |
| 32 | 31 | "UPDATE wvp_device_channel " + |
| 33 | 32 | "SET update_time=#{updateTime}" + |
| 34 | - "<if test='name != null'>, name=#{name}</if>" + | |
| 33 | + ", custom_name=#{name}" + | |
| 35 | 34 | "<if test='manufacture != null'>, manufacture=#{manufacture}</if>" + |
| 36 | 35 | "<if test='model != null'>, model=#{model}</if>" + |
| 37 | 36 | "<if test='owner != null'>, owner=#{owner}</if>" + |
| ... | ... | @@ -49,12 +48,12 @@ public interface DeviceChannelMapper { |
| 49 | 48 | "<if test='ipAddress != null'>, ip_address=#{ipAddress}</if>" + |
| 50 | 49 | "<if test='port != null'>, port=#{port}</if>" + |
| 51 | 50 | "<if test='password != null'>, password=#{password}</if>" + |
| 52 | - "<if test='PTZType != null'>, ptz_type=#{PTZType}</if>" + | |
| 51 | + "<if test='PTZType != null'>, custom_ptz_type=#{PTZType}</if>" + | |
| 53 | 52 | "<if test='status != null'>, status=#{status}</if>" + |
| 54 | 53 | "<if test='streamId != null'>, stream_id=#{streamId}</if>" + |
| 55 | 54 | "<if test='hasAudio != null'>, has_audio=#{hasAudio}</if>" + |
| 56 | - "<if test='longitude != null'>, longitude=#{longitude}</if>" + | |
| 57 | - "<if test='latitude != null'>, latitude=#{latitude}</if>" + | |
| 55 | + ", custom_longitude=#{longitude}" + | |
| 56 | + ", custom_latitude=#{latitude}" + | |
| 58 | 57 | "<if test='longitudeGcj02 != null'>, longitude_gcj02=#{longitudeGcj02}</if>" + |
| 59 | 58 | "<if test='latitudeGcj02 != null'>, latitude_gcj02=#{latitudeGcj02}</if>" + |
| 60 | 59 | "<if test='longitudeWgs84 != null'>, longitude_wgs84=#{longitudeWgs84}</if>" + |
| ... | ... | @@ -67,7 +66,43 @@ public interface DeviceChannelMapper { |
| 67 | 66 | |
| 68 | 67 | @Select(value = {" <script>" + |
| 69 | 68 | "SELECT " + |
| 70 | - "dc.* " + | |
| 69 | + "dc.id, " + | |
| 70 | + "dc.channel_id, " + | |
| 71 | + "COALESCE(dc.custom_name, dc.name) AS name, " + | |
| 72 | + "dc.manufacture, " + | |
| 73 | + "dc.model, " + | |
| 74 | + "dc.owner, " + | |
| 75 | + "dc.civil_code, " + | |
| 76 | + "dc.block, " + | |
| 77 | + "dc.address, " + | |
| 78 | + "dc.parent_id, " + | |
| 79 | + "dc.safety_way, " + | |
| 80 | + "dc.register_way, " + | |
| 81 | + "dc.cert_num, " + | |
| 82 | + "dc.certifiable, " + | |
| 83 | + "dc.err_code, " + | |
| 84 | + "dc.end_time, " + | |
| 85 | + "dc.secrecy, " + | |
| 86 | + "dc.ip_address, " + | |
| 87 | + "dc.port, " + | |
| 88 | + "dc.password, " + | |
| 89 | + "COALESCE(dc.custom_ptz_type, dc.ptz_type) AS ptz_type, " + | |
| 90 | + "dc.status, " + | |
| 91 | + "COALESCE(dc.custom_longitude, dc.longitude) AS longitude, " + | |
| 92 | + "COALESCE(dc.custom_latitude, dc.latitude) AS latitude, " + | |
| 93 | + "dc.stream_id, " + | |
| 94 | + "dc.device_id, " + | |
| 95 | + "dc.parental, " + | |
| 96 | + "dc.has_audio, " + | |
| 97 | + "dc.create_time, " + | |
| 98 | + "dc.update_time, " + | |
| 99 | + "dc.sub_count, " + | |
| 100 | + "dc.longitude_gcj02, " + | |
| 101 | + "dc.latitude_gcj02, " + | |
| 102 | + "dc.longitude_wgs84, " + | |
| 103 | + "dc.latitude_wgs84, " + | |
| 104 | + "dc.business_group_id, " + | |
| 105 | + "dc.gps_time " + | |
| 71 | 106 | "from " + |
| 72 | 107 | "wvp_device_channel dc " + |
| 73 | 108 | "WHERE " + |
| ... | ... | @@ -154,7 +189,7 @@ public interface DeviceChannelMapper { |
| 154 | 189 | " dc.id,\n" + |
| 155 | 190 | " dc.channel_id,\n" + |
| 156 | 191 | " dc.device_id,\n" + |
| 157 | - " dc.name,\n" + | |
| 192 | + " COALESCE(dc.custom_name, dc.name) AS name,\n" + | |
| 158 | 193 | " de.manufacturer,\n" + |
| 159 | 194 | " de.host_address,\n" + |
| 160 | 195 | " dc.sub_count,\n" + |
| ... | ... | @@ -392,10 +427,10 @@ public interface DeviceChannelMapper { |
| 392 | 427 | @Select("select * from wvp_device_channel where device_id=#{deviceId} and SUBSTRING(channel_id, 11, 3)=#{typeCode}") |
| 393 | 428 | List<DeviceChannel> getBusinessGroups(@Param("deviceId") String deviceId, @Param("typeCode") String typeCode); |
| 394 | 429 | |
| 395 | - @Select("select dc.id, dc.channel_id, dc.device_id, dc.name, dc.manufacture,dc.model,dc.owner, pc.civil_code,dc.block, " + | |
| 430 | + @Select("select dc.id, dc.channel_id, dc.device_id, COALESCE(dc.custom_name, dc.name) AS name, dc.manufacture,dc.model,dc.owner, pc.civil_code,dc.block, " + | |
| 396 | 431 | " dc.address, '0' as parental,'0' as channel_type, pc.id as parent_id, dc.safety_way, dc.register_way,dc.cert_num, dc.certifiable, " + |
| 397 | - " dc.err_code,dc.end_time, dc.secrecy, dc.ip_address, dc.port, dc.ptz_type, dc.password, dc.status, " + | |
| 398 | - " dc.longitude_wgs84 as longitude, dc.latitude_wgs84 as latitude, pc.business_group_id " + | |
| 432 | + " dc.err_code,dc.end_time, dc.secrecy, dc.ip_address, dc.port, COALESCE(dc.custom_ptz_type, dc.ptz_type) AS ptz_type, dc.password, dc.status, " + | |
| 433 | + " COALESCE(dc.custom_longitude, dc.longitude) AS longitude, COALESCE(dc.custom_latitude, dc.latitude) AS latitude, pc.business_group_id " + | |
| 399 | 434 | " from wvp_device_channel dc" + |
| 400 | 435 | " LEFT JOIN wvp_platform_gb_channel pgc on dc.id = pgc.device_channel_id" + |
| 401 | 436 | " LEFT JOIN wvp_platform_catalog pc on pgc.catalog_id = pc.id and pgc.platform_id = pc.platform_id" + |
| ... | ... | @@ -457,7 +492,44 @@ public interface DeviceChannelMapper { |
| 457 | 492 | void clearPlay(String deviceId); |
| 458 | 493 | // 设备主子码流逻辑END |
| 459 | 494 | @Select(value = {" <script>" + |
| 460 | - "select * " + | |
| 495 | + "SELECT id,\n" + | |
| 496 | + " channel_id,\n" + | |
| 497 | + " COALESCE(custom_name, name) AS name,\n" + | |
| 498 | + " custom_name,\n" + | |
| 499 | + " manufacture,\n" + | |
| 500 | + " model,\n" + | |
| 501 | + " owner,\n" + | |
| 502 | + " civil_code,\n" + | |
| 503 | + " block,\n" + | |
| 504 | + " address,\n" + | |
| 505 | + " parent_id,\n" + | |
| 506 | + " safety_way,\n" + | |
| 507 | + " register_way,\n" + | |
| 508 | + " cert_num,\n" + | |
| 509 | + " certifiable,\n" + | |
| 510 | + " err_code,\n" + | |
| 511 | + " end_time,\n" + | |
| 512 | + " secrecy,\n" + | |
| 513 | + " ip_address,\n" + | |
| 514 | + " port,\n" + | |
| 515 | + " password,\n" + | |
| 516 | + " COALESCE(custom_ptz_type, ptz_type) AS ptz_type,\n" + | |
| 517 | + " status,\n" + | |
| 518 | + " COALESCE(custom_longitude, longitude) AS longitude,\n" + | |
| 519 | + " COALESCE(custom_latitude, latitude) AS latitude,\n" + | |
| 520 | + " stream_id,\n" + | |
| 521 | + " device_id,\n" + | |
| 522 | + " parental,\n" + | |
| 523 | + " has_audio,\n" + | |
| 524 | + " create_time,\n" + | |
| 525 | + " update_time,\n" + | |
| 526 | + " sub_count,\n" + | |
| 527 | + " longitude_gcj02,\n" + | |
| 528 | + " latitude_gcj02,\n" + | |
| 529 | + " longitude_wgs84,\n" + | |
| 530 | + " latitude_wgs84,\n" + | |
| 531 | + " business_group_id,\n" + | |
| 532 | + " gps_time\n" + | |
| 461 | 533 | "from wvp_device_channel " + |
| 462 | 534 | "where device_id=#{deviceId}" + |
| 463 | 535 | " <if test='parentId != null and parentId != deviceId'> and parent_id = #{parentId} </if>" + | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/GbStreamMapper.java
| ... | ... | @@ -158,7 +158,7 @@ public interface GbStreamMapper { |
| 158 | 158 | " <foreach collection='list' item='item' index='index' separator=';'>"+ |
| 159 | 159 | "UPDATE wvp_gb_stream " + |
| 160 | 160 | " SET name=#{item.name},"+ |
| 161 | - " gb_id=#{item.gb_id}"+ | |
| 161 | + " gb_id=#{item.gbId}"+ | |
| 162 | 162 | " WHERE app=#{item.app} and stream=#{item.stream}"+ |
| 163 | 163 | "</foreach>"+ |
| 164 | 164 | "</script>") | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/MediaServerMapper.java
| ... | ... | @@ -31,6 +31,8 @@ public interface MediaServerMapper { |
| 31 | 31 | "rtp_port_range,"+ |
| 32 | 32 | "send_rtp_port_range,"+ |
| 33 | 33 | "record_assist_port,"+ |
| 34 | + "record_day,"+ | |
| 35 | + "record_path,"+ | |
| 34 | 36 | "default_server,"+ |
| 35 | 37 | "create_time,"+ |
| 36 | 38 | "update_time,"+ |
| ... | ... | @@ -55,6 +57,8 @@ public interface MediaServerMapper { |
| 55 | 57 | "#{rtpPortRange}, " + |
| 56 | 58 | "#{sendRtpPortRange}, " + |
| 57 | 59 | "#{recordAssistPort}, " + |
| 60 | + "#{recordDay}, " + | |
| 61 | + "#{recordPath}, " + | |
| 58 | 62 | "#{defaultServer}, " + |
| 59 | 63 | "#{createTime}, " + |
| 60 | 64 | "#{updateTime}, " + |
| ... | ... | @@ -82,6 +86,8 @@ public interface MediaServerMapper { |
| 82 | 86 | "<if test=\"secret != null\">, secret=#{secret}</if>" + |
| 83 | 87 | "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" + |
| 84 | 88 | "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" + |
| 89 | + "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" + | |
| 90 | + "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" + | |
| 85 | 91 | "WHERE id=#{id}"+ |
| 86 | 92 | " </script>"}) |
| 87 | 93 | int update(MediaServerItem mediaServerItem); |
| ... | ... | @@ -105,6 +111,8 @@ public interface MediaServerMapper { |
| 105 | 111 | "<if test=\"sendRtpPortRange != null\">, send_rtp_port_range=#{sendRtpPortRange}</if>" + |
| 106 | 112 | "<if test=\"secret != null\">, secret=#{secret}</if>" + |
| 107 | 113 | "<if test=\"recordAssistPort != null\">, record_assist_port=#{recordAssistPort}</if>" + |
| 114 | + "<if test=\"recordDay != null\">, record_day=#{recordDay}</if>" + | |
| 115 | + "<if test=\"recordPath != null\">, record_path=#{recordPath}</if>" + | |
| 108 | 116 | "<if test=\"hookAliveInterval != null\">, hook_alive_interval=#{hookAliveInterval}</if>" + |
| 109 | 117 | "WHERE ip=#{ip} and http_port=#{httpPort}"+ |
| 110 | 118 | " </script>"}) |
| ... | ... | @@ -130,4 +138,8 @@ public interface MediaServerMapper { |
| 130 | 138 | |
| 131 | 139 | @Select("SELECT * FROM wvp_media_server WHERE default_server=true") |
| 132 | 140 | MediaServerItem queryDefault(); |
| 141 | + | |
| 142 | + @Select("SELECT * FROM wvp_media_server WHERE record_assist_port > 0") | |
| 143 | + List<MediaServerItem> queryAllWithAssistPort(); | |
| 144 | + | |
| 133 | 145 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformChannelMapper.java
| ... | ... | @@ -117,8 +117,6 @@ public interface PlatformChannelMapper { |
| 117 | 117 | "where dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}") |
| 118 | 118 | List<Device> queryDeviceInfoByPlatformIdAndChannelId(@Param("platformId") String platformId, @Param("channelId") String channelId); |
| 119 | 119 | |
| 120 | - @Select("SELECT pgc.platform_id from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id='${channelId}'") | |
| 121 | - List<String> queryParentPlatformByChannelId(String channelId); | |
| 122 | - | |
| 123 | - | |
| 120 | + @Select("SELECT pgc.platform_id from wvp_platform_gb_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_id=#{channelId}") | |
| 121 | + List<String> queryParentPlatformByChannelId(@Param("channelId") String channelId); | |
| 124 | 122 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/PlatformGbStreamMapper.java
| ... | ... | @@ -103,6 +103,9 @@ public interface PlatformGbStreamMapper { |
| 103 | 103 | "</script>") |
| 104 | 104 | void delByAppAndStreamsByPlatformId(@Param("gbStreams") List<GbStream> gbStreams, @Param("platformId") String platformId); |
| 105 | 105 | |
| 106 | - @Delete("DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId} and catalog_id=#{catalogId}") | |
| 106 | + @Delete("<script> "+ | |
| 107 | + "DELETE from wvp_platform_gb_stream WHERE platform_id=#{platformId}" + | |
| 108 | + " <if test='catalogId != null' > and catalog_id=#{catalogId}</if>" + | |
| 109 | + "</script>") | |
| 107 | 110 | int delByPlatformAndCatalogId(@Param("platformId") String platformId, @Param("catalogId") String catalogId); |
| 108 | 111 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/dao/StreamPushMapper.java
| ... | ... | @@ -13,9 +13,9 @@ import java.util.List; |
| 13 | 13 | public interface StreamPushMapper { |
| 14 | 14 | |
| 15 | 15 | @Insert("INSERT INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " + |
| 16 | - "push_time, alive_second, media_server_id, update_time, create_time, push_ing, self) VALUES" + | |
| 16 | + "push_time, alive_second, media_server_id, server_id, update_time, create_time, push_ing, self) VALUES" + | |
| 17 | 17 | "(#{app}, #{stream}, #{totalReaderCount}, #{originType}, #{originTypeStr}, " + |
| 18 | - "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{updateTime} , #{createTime}, " + | |
| 18 | + "#{pushTime}, #{aliveSecond}, #{mediaServerId} , #{serverId} , #{updateTime} , #{createTime}, " + | |
| 19 | 19 | "#{pushIng}, #{self} )") |
| 20 | 20 | int add(StreamPushItem streamPushItem); |
| 21 | 21 | |
| ... | ... | @@ -24,6 +24,7 @@ public interface StreamPushMapper { |
| 24 | 24 | "UPDATE wvp_stream_push " + |
| 25 | 25 | "SET update_time=#{updateTime}" + |
| 26 | 26 | "<if test=\"mediaServerId != null\">, media_server_id=#{mediaServerId}</if>" + |
| 27 | + "<if test=\"serverId != null\">, server_id=#{serverId}</if>" + | |
| 27 | 28 | "<if test=\"totalReaderCount != null\">, total_reader_count=#{totalReaderCount}</if>" + |
| 28 | 29 | "<if test=\"originType != null\">, origin_type=#{originType}</if>" + |
| 29 | 30 | "<if test=\"originTypeStr != null\">, origin_type_str=#{originTypeStr}</if>" + |
| ... | ... | @@ -89,10 +90,10 @@ public interface StreamPushMapper { |
| 89 | 90 | |
| 90 | 91 | @Insert("<script>" + |
| 91 | 92 | "Insert INTO wvp_stream_push (app, stream, total_reader_count, origin_type, origin_type_str, " + |
| 92 | - "create_time, alive_second, media_server_id, status, push_ing) " + | |
| 93 | + "create_time, alive_second, media_server_id, server_id, status, push_ing) " + | |
| 93 | 94 | "VALUES <foreach collection='streamPushItems' item='item' index='index' separator=','>" + |
| 94 | 95 | "( #{item.app}, #{item.stream}, #{item.totalReaderCount}, #{item.originType}, " + |
| 95 | - "#{item.originTypeStr},#{item.createTime}, #{item.aliveSecond}, #{item.mediaServerId}, #{item.status} ," + | |
| 96 | + "#{item.originTypeStr},#{item.createTime}, #{item.aliveSecond}, #{item.mediaServerId},#{item.serverId}, #{item.status} ," + | |
| 96 | 97 | " #{item.pushIng} )" + |
| 97 | 98 | " </foreach>" + |
| 98 | 99 | "</script>") | ... | ... |
src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java
| ... | ... | @@ -609,14 +609,13 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 609 | 609 | @Override |
| 610 | 610 | public void sendDeviceOrChannelStatus(String deviceId, String channelId, boolean online) { |
| 611 | 611 | String key = VideoManagerConstants.VM_MSG_SUBSCRIBE_DEVICE_STATUS; |
| 612 | - logger.info("[redis通知] 发送 推送设备/通道状态, {}/{}-{}", deviceId, channelId, online); | |
| 613 | 612 | StringBuilder msg = new StringBuilder(); |
| 614 | 613 | msg.append(deviceId); |
| 615 | 614 | if (channelId != null) { |
| 616 | 615 | msg.append(":").append(channelId); |
| 617 | 616 | } |
| 618 | 617 | msg.append(" ").append(online? "ON":"OFF"); |
| 619 | - logger.info("[redis通知] 推送状态-> {} ", msg); | |
| 618 | + logger.info("[redis通知] 推送设备/通道状态-> {} ", msg); | |
| 620 | 619 | // 使用 RedisTemplate<Object, Object> 发送字符串消息会导致发送的消息多带了双引号 |
| 621 | 620 | stringRedisTemplate.convertAndSend(key, msg.toString()); |
| 622 | 621 | } |
| ... | ... | @@ -650,4 +649,20 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { |
| 650 | 649 | logger.info("[redis发送通知] 发送 上级平台停止观看 {}: {}/{}->{}", key, msg.getApp(), msg.getStream(), msg.getPlatFormId()); |
| 651 | 650 | redisTemplate.convertAndSend(key, JSON.toJSON(msg)); |
| 652 | 651 | } |
| 652 | + | |
| 653 | + @Override | |
| 654 | + public void addPushListItem(String app, String stream, OnStreamChangedHookParam param) { | |
| 655 | + String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; | |
| 656 | + redisTemplate.opsForValue().set(key, param); | |
| 657 | + } | |
| 658 | + | |
| 659 | + @Override | |
| 660 | + public void removePushListItem(String app, String stream, String mediaServerId) { | |
| 661 | + String key = VideoManagerConstants.PUSH_STREAM_LIST + app + "_" + stream; | |
| 662 | + OnStreamChangedHookParam param = (OnStreamChangedHookParam)redisTemplate.opsForValue().get(key); | |
| 663 | + if (param != null && param.getMediaServerId().equalsIgnoreCase(mediaServerId)) { | |
| 664 | + redisTemplate.delete(key); | |
| 665 | + } | |
| 666 | + | |
| 667 | + } | |
| 653 | 668 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/CloudRecordUtils.java
0 → 100644
| 1 | +package com.genersoft.iot.vmp.utils; | |
| 2 | + | |
| 3 | +import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; | |
| 4 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 5 | + | |
| 6 | +public class CloudRecordUtils { | |
| 7 | + | |
| 8 | + public static DownloadFileInfo getDownloadFilePath(MediaServerItem mediaServerItem, String filePath) { | |
| 9 | + DownloadFileInfo downloadFileInfo = new DownloadFileInfo(); | |
| 10 | + | |
| 11 | + String pathTemplate = "%s://%s:%s/index/api/downloadFile?file_path=" + filePath; | |
| 12 | + | |
| 13 | + downloadFileInfo.setHttpPath(String.format(pathTemplate, "http", mediaServerItem.getStreamIp(), | |
| 14 | + mediaServerItem.getHttpPort())); | |
| 15 | + | |
| 16 | + if (mediaServerItem.getHttpSSlPort() > 0) { | |
| 17 | + downloadFileInfo.setHttpsPath(String.format(pathTemplate, "https", mediaServerItem.getStreamIp(), | |
| 18 | + mediaServerItem.getHttpSSlPort())); | |
| 19 | + } | |
| 20 | + return downloadFileInfo; | |
| 21 | + } | |
| 22 | +} | ... | ... |
src/main/java/com/genersoft/iot/vmp/utils/DateUtil.java
| ... | ... | @@ -40,11 +40,17 @@ public class DateUtil { |
| 40 | 40 | */ |
| 41 | 41 | public static final String URL_PATTERN = "yyyyMMddHHmmss"; |
| 42 | 42 | |
| 43 | + /** | |
| 44 | + * 日期格式 | |
| 45 | + */ | |
| 46 | + public static final String date_PATTERN = "yyyy-MM-dd"; | |
| 47 | + | |
| 43 | 48 | public static final String zoneStr = "Asia/Shanghai"; |
| 44 | 49 | |
| 45 | 50 | public static final DateTimeFormatter formatterCompatibleISO8601 = DateTimeFormatter.ofPattern(ISO8601_COMPATIBLE_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 46 | 51 | public static final DateTimeFormatter formatterISO8601 = DateTimeFormatter.ofPattern(ISO8601_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 47 | 52 | public static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern(PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 53 | + public static final DateTimeFormatter DateFormatter = DateTimeFormatter.ofPattern(date_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); | |
| 48 | 54 | public static final DateTimeFormatter urlFormatter = DateTimeFormatter.ofPattern(URL_PATTERN, Locale.getDefault()).withZone(ZoneId.of(zoneStr)); |
| 49 | 55 | |
| 50 | 56 | public static String yyyy_MM_dd_HH_mm_ssToISO8601(String formatTime) { |
| ... | ... | @@ -72,6 +78,22 @@ public class DateUtil { |
| 72 | 78 | } |
| 73 | 79 | |
| 74 | 80 | /** |
| 81 | + * 时间戳 转 yyyy_MM_dd_HH_mm_ss | |
| 82 | + */ | |
| 83 | + public static String timestampTo_yyyy_MM_dd_HH_mm_ss(long timestamp) { | |
| 84 | + Instant instant = Instant.ofEpochSecond(timestamp); | |
| 85 | + return formatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr))); | |
| 86 | + } | |
| 87 | + | |
| 88 | + /** | |
| 89 | + * 时间戳 转 yyyy_MM_dd | |
| 90 | + */ | |
| 91 | + public static String timestampTo_yyyy_MM_dd(long timestamp) { | |
| 92 | + Instant instant = Instant.ofEpochMilli(timestamp); | |
| 93 | + return DateFormatter.format(LocalDateTime.ofInstant(instant, ZoneId.of(zoneStr))); | |
| 94 | + } | |
| 95 | + | |
| 96 | + /** | |
| 75 | 97 | * 获取当前时间 |
| 76 | 98 | * @return |
| 77 | 99 | */ |
| ... | ... | @@ -117,4 +139,13 @@ public class DateUtil { |
| 117 | 139 | Instant beforeInstant = Instant.from(formatter.parse(keepaliveTime)); |
| 118 | 140 | return ChronoUnit.MILLIS.between(beforeInstant, Instant.now()); |
| 119 | 141 | } |
| 142 | + | |
| 143 | + public static long getDifference(String startTime, String endTime) { | |
| 144 | + if (ObjectUtils.isEmpty(startTime) || ObjectUtils.isEmpty(endTime)) { | |
| 145 | + return 0; | |
| 146 | + } | |
| 147 | + Instant startInstant = Instant.from(formatter.parse(startTime)); | |
| 148 | + Instant endInstant = Instant.from(formatter.parse(endTime)); | |
| 149 | + return ChronoUnit.MILLIS.between(endInstant, startInstant); | |
| 150 | + } | |
| 120 | 151 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/bean/StreamContent.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.bean; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 4 | 5 | import io.swagger.v3.oas.annotations.media.Schema; |
| 5 | 6 | |
| 6 | 7 | @Schema(description = "流信息") |
| ... | ... | @@ -93,6 +94,9 @@ public class StreamContent { |
| 93 | 94 | @Schema(description = "结束时间") |
| 94 | 95 | private String endTime; |
| 95 | 96 | |
| 97 | + @Schema(description = "文件下载地址(录像下载使用)") | |
| 98 | + private DownloadFileInfo downLoadFilePath; | |
| 99 | + | |
| 96 | 100 | private double progress; |
| 97 | 101 | |
| 98 | 102 | public StreamContent(StreamInfo streamInfo) { |
| ... | ... | @@ -170,6 +174,10 @@ public class StreamContent { |
| 170 | 174 | this.startTime = streamInfo.getStartTime(); |
| 171 | 175 | this.endTime = streamInfo.getEndTime(); |
| 172 | 176 | this.progress = streamInfo.getProgress(); |
| 177 | + | |
| 178 | + if (streamInfo.getDownLoadFilePath() != null) { | |
| 179 | + this.downLoadFilePath = streamInfo.getDownLoadFilePath(); | |
| 180 | + } | |
| 173 | 181 | } |
| 174 | 182 | |
| 175 | 183 | public String getApp() { |
| ... | ... | @@ -411,4 +419,12 @@ public class StreamContent { |
| 411 | 419 | public void setProgress(double progress) { |
| 412 | 420 | this.progress = progress; |
| 413 | 421 | } |
| 422 | + | |
| 423 | + public DownloadFileInfo getDownLoadFilePath() { | |
| 424 | + return downLoadFilePath; | |
| 425 | + } | |
| 426 | + | |
| 427 | + public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) { | |
| 428 | + this.downLoadFilePath = downLoadFilePath; | |
| 429 | + } | |
| 414 | 430 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/cloudRecord/CloudRecordController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.cloudRecord; |
| 2 | 2 | |
| 3 | +import com.alibaba.fastjson2.JSONArray; | |
| 3 | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 4 | 5 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 5 | 6 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 7 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 6 | 8 | import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; |
| 7 | 9 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| 8 | -import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; | |
| 9 | 10 | import com.genersoft.iot.vmp.media.zlm.dto.MediaServerItem; |
| 11 | +import com.genersoft.iot.vmp.service.ICloudRecordService; | |
| 10 | 12 | import com.genersoft.iot.vmp.service.IMediaServerService; |
| 13 | +import com.genersoft.iot.vmp.service.bean.CloudRecordItem; | |
| 14 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 11 | 15 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 12 | -import com.genersoft.iot.vmp.vmanager.bean.PageInfo; | |
| 13 | -import com.genersoft.iot.vmp.vmanager.bean.RecordFile; | |
| 16 | +import com.github.pagehelper.PageInfo; | |
| 14 | 17 | import io.swagger.v3.oas.annotations.Operation; |
| 15 | 18 | import io.swagger.v3.oas.annotations.Parameter; |
| 19 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 16 | 20 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 17 | 21 | import org.apache.commons.lang3.ObjectUtils; |
| 18 | 22 | import org.slf4j.Logger; |
| ... | ... | @@ -32,40 +36,27 @@ import java.util.List; |
| 32 | 36 | @RequestMapping("/api/cloud/record") |
| 33 | 37 | public class CloudRecordController { |
| 34 | 38 | |
| 35 | - @Autowired | |
| 36 | - private ZLMServerFactory zlmServerFactory; | |
| 37 | - | |
| 38 | - @Autowired | |
| 39 | - private SendRtpPortManager sendRtpPortManager; | |
| 40 | 39 | |
| 41 | 40 | private final static Logger logger = LoggerFactory.getLogger(CloudRecordController.class); |
| 42 | 41 | |
| 43 | 42 | @Autowired |
| 44 | - private ZlmHttpHookSubscribe hookSubscribe; | |
| 43 | + private ICloudRecordService cloudRecordService; | |
| 45 | 44 | |
| 46 | 45 | @Autowired |
| 47 | 46 | private IMediaServerService mediaServerService; |
| 48 | 47 | |
| 49 | - @Autowired | |
| 50 | - private UserSetting userSetting; | |
| 51 | - | |
| 52 | - @Autowired | |
| 53 | - private DynamicTask dynamicTask; | |
| 54 | - | |
| 55 | - @Autowired | |
| 56 | - private RedisTemplate<Object, Object> redisTemplate; | |
| 57 | 48 | |
| 58 | 49 | @ResponseBody |
| 59 | 50 | @GetMapping("/date/list") |
| 60 | - @Operation(summary = "查询存在云端录像的日期") | |
| 51 | + @Operation(summary = "查询存在云端录像的日期", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 61 | 52 | @Parameter(name = "app", description = "应用名", required = true) |
| 62 | 53 | @Parameter(name = "stream", description = "流ID", required = true) |
| 63 | 54 | @Parameter(name = "year", description = "年,置空则查询当年", required = false) |
| 64 | 55 | @Parameter(name = "month", description = "月,置空则查询当月", required = false) |
| 65 | 56 | @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部", required = false) |
| 66 | 57 | public List<String> openRtpServer( |
| 67 | - @RequestParam String app, | |
| 68 | - @RequestParam String stream, | |
| 58 | + @RequestParam(required = true) String app, | |
| 59 | + @RequestParam(required = true) String stream, | |
| 69 | 60 | @RequestParam(required = false) int year, |
| 70 | 61 | @RequestParam(required = false) int month, |
| 71 | 62 | @RequestParam(required = false) String mediaServerId |
| ... | ... | @@ -95,26 +86,28 @@ public class CloudRecordController { |
| 95 | 86 | return new ArrayList<>(); |
| 96 | 87 | } |
| 97 | 88 | |
| 98 | - return mediaServerService.getRecordDates(app, stream, year, month, mediaServerItems); | |
| 89 | + return cloudRecordService.getDateList(app, stream, year, month, mediaServerItems); | |
| 99 | 90 | } |
| 100 | 91 | |
| 101 | 92 | @ResponseBody |
| 102 | 93 | @GetMapping("/list") |
| 103 | - @Operation(summary = "分页查询云端录像") | |
| 104 | - @Parameter(name = "app", description = "应用名", required = true) | |
| 105 | - @Parameter(name = "stream", description = "流ID", required = true) | |
| 106 | - @Parameter(name = "page", description = "当前页", required = false) | |
| 107 | - @Parameter(name = "count", description = "每页查询数量", required = false) | |
| 108 | - @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = true) | |
| 109 | - @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = true) | |
| 94 | + @Operation(summary = "分页查询云端录像", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 95 | + @Parameter(name = "query", description = "检索内容", required = false) | |
| 96 | + @Parameter(name = "app", description = "应用名", required = false) | |
| 97 | + @Parameter(name = "stream", description = "流ID", required = false) | |
| 98 | + @Parameter(name = "page", description = "当前页", required = true) | |
| 99 | + @Parameter(name = "count", description = "每页查询数量", required = true) | |
| 100 | + @Parameter(name = "startTime", description = "开始时间(yyyy-MM-dd HH:mm:ss)", required = false) | |
| 101 | + @Parameter(name = "endTime", description = "结束时间(yyyy-MM-dd HH:mm:ss)", required = false) | |
| 110 | 102 | @Parameter(name = "mediaServerId", description = "流媒体ID,置空则查询全部流媒体", required = false) |
| 111 | - public PageInfo<RecordFile> openRtpServer( | |
| 112 | - @RequestParam String app, | |
| 113 | - @RequestParam String stream, | |
| 103 | + public PageInfo<CloudRecordItem> openRtpServer( | |
| 104 | + @RequestParam(required = false) String query, | |
| 105 | + @RequestParam(required = false) String app, | |
| 106 | + @RequestParam(required = false) String stream, | |
| 114 | 107 | @RequestParam int page, |
| 115 | 108 | @RequestParam int count, |
| 116 | - @RequestParam String startTime, | |
| 117 | - @RequestParam String endTime, | |
| 109 | + @RequestParam(required = false) String startTime, | |
| 110 | + @RequestParam(required = false) String endTime, | |
| 118 | 111 | @RequestParam(required = false) String mediaServerId |
| 119 | 112 | |
| 120 | 113 | ) { |
| ... | ... | @@ -133,13 +126,128 @@ public class CloudRecordController { |
| 133 | 126 | mediaServerItems = mediaServerService.getAll(); |
| 134 | 127 | } |
| 135 | 128 | if (mediaServerItems.isEmpty()) { |
| 136 | - return new PageInfo<>(); | |
| 129 | + throw new ControllerException(ErrorCode.ERROR100.getCode(), "当前无流媒体"); | |
| 130 | + } | |
| 131 | + if (query != null && ObjectUtils.isEmpty(query.trim())) { | |
| 132 | + query = null; | |
| 133 | + } | |
| 134 | + if (app != null && ObjectUtils.isEmpty(app.trim())) { | |
| 135 | + app = null; | |
| 136 | + } | |
| 137 | + if (stream != null && ObjectUtils.isEmpty(stream.trim())) { | |
| 138 | + stream = null; | |
| 139 | + } | |
| 140 | + if (startTime != null && ObjectUtils.isEmpty(startTime.trim())) { | |
| 141 | + startTime = null; | |
| 142 | + } | |
| 143 | + if (endTime != null && ObjectUtils.isEmpty(endTime.trim())) { | |
| 144 | + endTime = null; | |
| 137 | 145 | } |
| 138 | - List<RecordFile> records = mediaServerService.getRecords(app, stream, startTime, endTime, mediaServerItems); | |
| 139 | - PageInfo<RecordFile> pageInfo = new PageInfo<>(records); | |
| 140 | - pageInfo.startPage(page, count); | |
| 141 | - return pageInfo; | |
| 146 | + return cloudRecordService.getList(page, count, query, app, stream, startTime, endTime, mediaServerItems); | |
| 142 | 147 | } |
| 143 | 148 | |
| 149 | + @ResponseBody | |
| 150 | + @GetMapping("/task/add") | |
| 151 | + @Operation(summary = "添加合并任务") | |
| 152 | + @Parameter(name = "app", description = "应用名", required = false) | |
| 153 | + @Parameter(name = "stream", description = "流ID", required = false) | |
| 154 | + @Parameter(name = "mediaServerId", description = "流媒体ID", required = false) | |
| 155 | + @Parameter(name = "startTime", description = "鉴权ID", required = false) | |
| 156 | + @Parameter(name = "endTime", description = "鉴权ID", required = false) | |
| 157 | + @Parameter(name = "callId", description = "鉴权ID", required = false) | |
| 158 | + @Parameter(name = "remoteHost", description = "返回地址时的远程地址", required = false) | |
| 159 | + public String addTask( | |
| 160 | + @RequestParam(required = false) String app, | |
| 161 | + @RequestParam(required = false) String stream, | |
| 162 | + @RequestParam(required = false) String mediaServerId, | |
| 163 | + @RequestParam(required = false) String startTime, | |
| 164 | + @RequestParam(required = false) String endTime, | |
| 165 | + @RequestParam(required = false) String callId, | |
| 166 | + @RequestParam(required = false) String remoteHost | |
| 167 | + ){ | |
| 168 | + return cloudRecordService.addTask(app, stream, mediaServerId, startTime, endTime, callId, remoteHost); | |
| 169 | + } | |
| 170 | + | |
| 171 | + @ResponseBody | |
| 172 | + @GetMapping("/task/list") | |
| 173 | + @Operation(summary = "查询合并任务") | |
| 174 | + @Parameter(name = "taskId", description = "任务Id", required = false) | |
| 175 | + @Parameter(name = "mediaServerId", description = "流媒体ID", required = false) | |
| 176 | + @Parameter(name = "isEnd", description = "是否结束", required = false) | |
| 177 | + public JSONArray queryTaskList( | |
| 178 | + @RequestParam(required = false) String app, | |
| 179 | + @RequestParam(required = false) String stream, | |
| 180 | + @RequestParam(required = false) String callId, | |
| 181 | + @RequestParam(required = false) String taskId, | |
| 182 | + @RequestParam(required = false) String mediaServerId, | |
| 183 | + @RequestParam(required = false) Boolean isEnd | |
| 184 | + ){ | |
| 185 | + return cloudRecordService.queryTask(app, stream, callId, taskId, mediaServerId, isEnd); | |
| 186 | + } | |
| 144 | 187 | |
| 188 | + @ResponseBody | |
| 189 | + @GetMapping("/collect/add") | |
| 190 | + @Operation(summary = "添加收藏") | |
| 191 | + @Parameter(name = "app", description = "应用名", required = false) | |
| 192 | + @Parameter(name = "stream", description = "流ID", required = false) | |
| 193 | + @Parameter(name = "mediaServerId", description = "流媒体ID", required = false) | |
| 194 | + @Parameter(name = "startTime", description = "鉴权ID", required = false) | |
| 195 | + @Parameter(name = "endTime", description = "鉴权ID", required = false) | |
| 196 | + @Parameter(name = "callId", description = "鉴权ID", required = false) | |
| 197 | + @Parameter(name = "recordId", description = "录像记录的ID,用于精准收藏一个视频文件", required = false) | |
| 198 | + public int addCollect( | |
| 199 | + @RequestParam(required = false) String app, | |
| 200 | + @RequestParam(required = false) String stream, | |
| 201 | + @RequestParam(required = false) String mediaServerId, | |
| 202 | + @RequestParam(required = false) String startTime, | |
| 203 | + @RequestParam(required = false) String endTime, | |
| 204 | + @RequestParam(required = false) String callId, | |
| 205 | + @RequestParam(required = false) Integer recordId | |
| 206 | + ){ | |
| 207 | + logger.info("[云端录像] 添加收藏,app={},stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}", | |
| 208 | + app, stream, mediaServerId, startTime, endTime, callId, recordId); | |
| 209 | + if (recordId != null) { | |
| 210 | + return cloudRecordService.changeCollectById(recordId, true); | |
| 211 | + }else { | |
| 212 | + return cloudRecordService.changeCollect(true, app, stream, mediaServerId, startTime, endTime, callId); | |
| 213 | + } | |
| 214 | + } | |
| 215 | + | |
| 216 | + @ResponseBody | |
| 217 | + @GetMapping("/collect/delete") | |
| 218 | + @Operation(summary = "移除收藏") | |
| 219 | + @Parameter(name = "app", description = "应用名", required = false) | |
| 220 | + @Parameter(name = "stream", description = "流ID", required = false) | |
| 221 | + @Parameter(name = "mediaServerId", description = "流媒体ID", required = false) | |
| 222 | + @Parameter(name = "startTime", description = "鉴权ID", required = false) | |
| 223 | + @Parameter(name = "endTime", description = "鉴权ID", required = false) | |
| 224 | + @Parameter(name = "callId", description = "鉴权ID", required = false) | |
| 225 | + @Parameter(name = "recordId", description = "录像记录的ID,用于精准精准移除一个视频文件的收藏", required = false) | |
| 226 | + public int deleteCollect( | |
| 227 | + @RequestParam(required = false) String app, | |
| 228 | + @RequestParam(required = false) String stream, | |
| 229 | + @RequestParam(required = false) String mediaServerId, | |
| 230 | + @RequestParam(required = false) String startTime, | |
| 231 | + @RequestParam(required = false) String endTime, | |
| 232 | + @RequestParam(required = false) String callId, | |
| 233 | + @RequestParam(required = false) Integer recordId | |
| 234 | + ){ | |
| 235 | + logger.info("[云端录像] 移除收藏,app={},stream={},mediaServerId={},startTime={},endTime={},callId={},recordId={}", | |
| 236 | + app, stream, mediaServerId, startTime, endTime, callId, recordId); | |
| 237 | + if (recordId != null) { | |
| 238 | + return cloudRecordService.changeCollectById(recordId, false); | |
| 239 | + }else { | |
| 240 | + return cloudRecordService.changeCollect(false, app, stream, mediaServerId, startTime, endTime, callId); | |
| 241 | + } | |
| 242 | + } | |
| 243 | + | |
| 244 | + @ResponseBody | |
| 245 | + @GetMapping("/play/path") | |
| 246 | + @Operation(summary = "获取播放地址") | |
| 247 | + @Parameter(name = "recordId", description = "录像记录的ID", required = true) | |
| 248 | + public DownloadFileInfo getPlayUrlPath( | |
| 249 | + @RequestParam(required = true) Integer recordId | |
| 250 | + ){ | |
| 251 | + return cloudRecordService.getPlayUrlPath(recordId); | |
| 252 | + } | |
| 145 | 253 | } | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/MobilePosition/MobilePositionController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.gb28181.MobilePosition; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 4 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| ... | ... | @@ -13,6 +14,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 13 | 14 | import com.github.pagehelper.util.StringUtil; |
| 14 | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 15 | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| 17 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 16 | 18 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 17 | 19 | import org.slf4j.Logger; |
| 18 | 20 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -59,7 +61,7 @@ public class MobilePositionController { |
| 59 | 61 | * @param end 结束时间 |
| 60 | 62 | * @return |
| 61 | 63 | */ |
| 62 | - @Operation(summary = "查询历史轨迹") | |
| 64 | + @Operation(summary = "查询历史轨迹", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 63 | 65 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 64 | 66 | @Parameter(name = "channelId", description = "通道国标编号") |
| 65 | 67 | @Parameter(name = "start", description = "开始时间") |
| ... | ... | @@ -84,7 +86,7 @@ public class MobilePositionController { |
| 84 | 86 | * @param deviceId 设备ID |
| 85 | 87 | * @return |
| 86 | 88 | */ |
| 87 | - @Operation(summary = "查询设备最新位置") | |
| 89 | + @Operation(summary = "查询设备最新位置", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 88 | 90 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 89 | 91 | @GetMapping("/latest/{deviceId}") |
| 90 | 92 | public MobilePosition latestPosition(@PathVariable String deviceId) { |
| ... | ... | @@ -96,7 +98,7 @@ public class MobilePositionController { |
| 96 | 98 | * @param deviceId 设备ID |
| 97 | 99 | * @return |
| 98 | 100 | */ |
| 99 | - @Operation(summary = "获取移动位置信息") | |
| 101 | + @Operation(summary = "获取移动位置信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 100 | 102 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 101 | 103 | @GetMapping("/realtime/{deviceId}") |
| 102 | 104 | public DeferredResult<MobilePosition> realTimePosition(@PathVariable String deviceId) { |
| ... | ... | @@ -136,7 +138,7 @@ public class MobilePositionController { |
| 136 | 138 | * @param interval 上报时间间隔 |
| 137 | 139 | * @return true = 命令发送成功 |
| 138 | 140 | */ |
| 139 | - @Operation(summary = "订阅位置信息") | |
| 141 | + @Operation(summary = "订阅位置信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 140 | 142 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 141 | 143 | @Parameter(name = "expires", description = "订阅超时时间", required = true) |
| 142 | 144 | @Parameter(name = "interval", description = "上报时间间隔", required = true) |
| ... | ... | @@ -162,7 +164,7 @@ public class MobilePositionController { |
| 162 | 164 | * @param deviceId 设备ID |
| 163 | 165 | * @return true = 命令发送成功 |
| 164 | 166 | */ |
| 165 | - @Operation(summary = "数据位置信息格式处理") | |
| 167 | + @Operation(summary = "数据位置信息格式处理", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 166 | 168 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 167 | 169 | @GetMapping("/transform/{deviceId}") |
| 168 | 170 | public void positionTransform(@PathVariable String deviceId) { | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.gb28181.alarm; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 4 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| ... | ... | @@ -13,6 +14,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 13 | 14 | import com.github.pagehelper.PageInfo; |
| 14 | 15 | import io.swagger.v3.oas.annotations.Operation; |
| 15 | 16 | import io.swagger.v3.oas.annotations.Parameter; |
| 17 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 16 | 18 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 17 | 19 | import org.slf4j.Logger; |
| 18 | 20 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -56,7 +58,7 @@ public class AlarmController { |
| 56 | 58 | * @return |
| 57 | 59 | */ |
| 58 | 60 | @DeleteMapping("/delete") |
| 59 | - @Operation(summary = "删除报警") | |
| 61 | + @Operation(summary = "删除报警", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 60 | 62 | @Parameter(name = "id", description = "ID") |
| 61 | 63 | @Parameter(name = "deviceIds", description = "多个设备id,逗号分隔") |
| 62 | 64 | @Parameter(name = "time", description = "结束时间") |
| ... | ... | @@ -93,7 +95,7 @@ public class AlarmController { |
| 93 | 95 | * @return |
| 94 | 96 | */ |
| 95 | 97 | @GetMapping("/test/notify/alarm") |
| 96 | - @Operation(summary = "测试向上级/设备发送模拟报警通知") | |
| 98 | + @Operation(summary = "测试向上级/设备发送模拟报警通知", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 97 | 99 | @Parameter(name = "deviceId", description = "设备国标编号") |
| 98 | 100 | public void delete(@RequestParam String deviceId) { |
| 99 | 101 | Device device = storage.queryVideoDevice(deviceId); |
| ... | ... | @@ -141,7 +143,7 @@ public class AlarmController { |
| 141 | 143 | * @param endTime 结束时间 |
| 142 | 144 | * @return |
| 143 | 145 | */ |
| 144 | - @Operation(summary = "分页查询报警") | |
| 146 | + @Operation(summary = "分页查询报警", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 145 | 147 | @Parameter(name = "page",description = "当前页",required = true) |
| 146 | 148 | @Parameter(name = "count",description = "每页查询数量",required = true) |
| 147 | 149 | @Parameter(name = "deviceId",description = "设备id") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
| ... | ... | @@ -9,6 +9,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device; |
| 9 | 9 | |
| 10 | 10 | import com.alibaba.fastjson2.JSONObject; |
| 11 | 11 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 12 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 13 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 14 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| ... | ... | @@ -17,6 +18,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 17 | 18 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 18 | 19 | import io.swagger.v3.oas.annotations.Operation; |
| 19 | 20 | import io.swagger.v3.oas.annotations.Parameter; |
| 21 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 20 | 22 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 21 | 23 | import org.slf4j.Logger; |
| 22 | 24 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -57,7 +59,7 @@ public class DeviceConfig { |
| 57 | 59 | * @return |
| 58 | 60 | */ |
| 59 | 61 | @GetMapping("/basicParam/{deviceId}") |
| 60 | - @Operation(summary = "基本配置设置命令") | |
| 62 | + @Operation(summary = "基本配置设置命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 61 | 63 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 62 | 64 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 63 | 65 | @Parameter(name = "name", description = "名称") |
| ... | ... | @@ -113,7 +115,7 @@ public class DeviceConfig { |
| 113 | 115 | * @param channelId 通道ID |
| 114 | 116 | * @return |
| 115 | 117 | */ |
| 116 | - @Operation(summary = "设备配置查询请求") | |
| 118 | + @Operation(summary = "设备配置查询请求", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 117 | 119 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 118 | 120 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 119 | 121 | @Parameter(name = "configType", description = "配置类型") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
| ... | ... | @@ -9,6 +9,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device; |
| 9 | 9 | |
| 10 | 10 | import com.alibaba.fastjson2.JSONObject; |
| 11 | 11 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 12 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 13 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 14 | 15 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| ... | ... | @@ -17,6 +18,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 17 | 18 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 18 | 19 | import io.swagger.v3.oas.annotations.Operation; |
| 19 | 20 | import io.swagger.v3.oas.annotations.Parameter; |
| 21 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 20 | 22 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 21 | 23 | import org.slf4j.Logger; |
| 22 | 24 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -53,7 +55,7 @@ public class DeviceControl { |
| 53 | 55 | * |
| 54 | 56 | * @param deviceId 设备ID |
| 55 | 57 | */ |
| 56 | - @Operation(summary = "远程启动控制命令") | |
| 58 | + @Operation(summary = "远程启动控制命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 57 | 59 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 58 | 60 | @GetMapping("/teleboot/{deviceId}") |
| 59 | 61 | public void teleBootApi(@PathVariable String deviceId) { |
| ... | ... | @@ -76,7 +78,7 @@ public class DeviceControl { |
| 76 | 78 | * @param recordCmdStr Record:手动录像,StopRecord:停止手动录像 |
| 77 | 79 | * @param channelId 通道编码(可选) |
| 78 | 80 | */ |
| 79 | - @Operation(summary = "录像控制") | |
| 81 | + @Operation(summary = "录像控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 80 | 82 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 81 | 83 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 82 | 84 | @Parameter(name = "recordCmdStr", description = "命令, 可选值:Record(手动录像),StopRecord(停止手动录像)", required = true) |
| ... | ... | @@ -125,7 +127,7 @@ public class DeviceControl { |
| 125 | 127 | * @param deviceId 设备ID |
| 126 | 128 | * @param guardCmdStr SetGuard:布防,ResetGuard:撤防 |
| 127 | 129 | */ |
| 128 | - @Operation(summary = "布防/撤防命令") | |
| 130 | + @Operation(summary = "布防/撤防命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 129 | 131 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 130 | 132 | @Parameter(name = "guardCmdStr", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true) |
| 131 | 133 | @GetMapping("/guard/{deviceId}/{guardCmdStr}") |
| ... | ... | @@ -170,7 +172,7 @@ public class DeviceControl { |
| 170 | 172 | * @param alarmMethod 报警方式(可选) |
| 171 | 173 | * @param alarmType 报警类型(可选) |
| 172 | 174 | */ |
| 173 | - @Operation(summary = "报警复位") | |
| 175 | + @Operation(summary = "报警复位", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 174 | 176 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 175 | 177 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 176 | 178 | @Parameter(name = "alarmMethod", description = "报警方式") |
| ... | ... | @@ -217,7 +219,7 @@ public class DeviceControl { |
| 217 | 219 | * @param deviceId 设备ID |
| 218 | 220 | * @param channelId 通道ID |
| 219 | 221 | */ |
| 220 | - @Operation(summary = "强制关键帧") | |
| 222 | + @Operation(summary = "强制关键帧", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 221 | 223 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 222 | 224 | @Parameter(name = "channelId", description = "通道国标编号") |
| 223 | 225 | @GetMapping("/i_frame/{deviceId}") |
| ... | ... | @@ -249,7 +251,7 @@ public class DeviceControl { |
| 249 | 251 | * @param presetIndex 调用预置位编号(可选) |
| 250 | 252 | * @param channelId 通道编码(可选) |
| 251 | 253 | */ |
| 252 | - @Operation(summary = "看守位控制") | |
| 254 | + @Operation(summary = "看守位控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 253 | 255 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 254 | 256 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 255 | 257 | @Parameter(name = "enabled", description = "是否开启看守位 1:开启,0:关闭", required = true) |
| ... | ... | @@ -309,7 +311,7 @@ public class DeviceControl { |
| 309 | 311 | * @param lengthy 拉框宽度像素值 |
| 310 | 312 | * @return |
| 311 | 313 | */ |
| 312 | - @Operation(summary = "拉框放大") | |
| 314 | + @Operation(summary = "拉框放大", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 313 | 315 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 314 | 316 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 315 | 317 | @Parameter(name = "length", description = "播放窗口长度像素值", required = true) |
| ... | ... | @@ -359,7 +361,7 @@ public class DeviceControl { |
| 359 | 361 | * @param lengthy 拉框宽度像素值 |
| 360 | 362 | * @return |
| 361 | 363 | */ |
| 362 | - @Operation(summary = "拉框放大") | |
| 364 | + @Operation(summary = "拉框缩小", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 363 | 365 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 364 | 366 | @Parameter(name = "channelId", description = "通道国标编号") |
| 365 | 367 | @Parameter(name = "length", description = "播放窗口长度像素值", required = true) | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
| ... | ... | @@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device; |
| 3 | 3 | import com.alibaba.fastjson2.JSONObject; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 5 | 5 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 6 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; |
| 8 | 9 | import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; |
| ... | ... | @@ -23,6 +24,7 @@ import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 23 | 24 | import com.github.pagehelper.PageInfo; |
| 24 | 25 | import io.swagger.v3.oas.annotations.Operation; |
| 25 | 26 | import io.swagger.v3.oas.annotations.Parameter; |
| 27 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 26 | 28 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 27 | 29 | import org.apache.commons.compress.utils.IOUtils; |
| 28 | 30 | import org.apache.ibatis.annotations.Options; |
| ... | ... | @@ -85,7 +87,7 @@ public class DeviceQuery { |
| 85 | 87 | * @param deviceId 国标ID |
| 86 | 88 | * @return 国标设备 |
| 87 | 89 | */ |
| 88 | - @Operation(summary = "查询国标设备") | |
| 90 | + @Operation(summary = "查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 89 | 91 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 90 | 92 | @GetMapping("/devices/{deviceId}") |
| 91 | 93 | public Device devices(@PathVariable String deviceId){ |
| ... | ... | @@ -99,7 +101,7 @@ public class DeviceQuery { |
| 99 | 101 | * @param count 每页查询数量 |
| 100 | 102 | * @return 分页国标列表 |
| 101 | 103 | */ |
| 102 | - @Operation(summary = "分页查询国标设备") | |
| 104 | + @Operation(summary = "分页查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 103 | 105 | @Parameter(name = "page", description = "当前页", required = true) |
| 104 | 106 | @Parameter(name = "count", description = "每页查询数量", required = true) |
| 105 | 107 | @GetMapping("/devices") |
| ... | ... | @@ -123,7 +125,7 @@ public class DeviceQuery { |
| 123 | 125 | * @return 通道列表 |
| 124 | 126 | */ |
| 125 | 127 | @GetMapping("/devices/{deviceId}/channels") |
| 126 | - @Operation(summary = "分页查询通道") | |
| 128 | + @Operation(summary = "分页查询通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 127 | 129 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 128 | 130 | @Parameter(name = "page", description = "当前页", required = true) |
| 129 | 131 | @Parameter(name = "count", description = "每页查询数量", required = true) |
| ... | ... | @@ -149,7 +151,7 @@ public class DeviceQuery { |
| 149 | 151 | * @param deviceId 设备id |
| 150 | 152 | * @return |
| 151 | 153 | */ |
| 152 | - @Operation(summary = "同步设备通道") | |
| 154 | + @Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 153 | 155 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 154 | 156 | @GetMapping("/devices/{deviceId}/sync") |
| 155 | 157 | public WVPResult<SyncStatus> devicesSync(@PathVariable String deviceId){ |
| ... | ... | @@ -177,7 +179,7 @@ public class DeviceQuery { |
| 177 | 179 | * @param deviceId 设备id |
| 178 | 180 | * @return |
| 179 | 181 | */ |
| 180 | - @Operation(summary = "移除设备") | |
| 182 | + @Operation(summary = "移除设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 181 | 183 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 182 | 184 | @DeleteMapping("/devices/{deviceId}/delete") |
| 183 | 185 | public String delete(@PathVariable String deviceId){ |
| ... | ... | @@ -222,7 +224,7 @@ public class DeviceQuery { |
| 222 | 224 | * @param channelType 通道类型 |
| 223 | 225 | * @return 子通道列表 |
| 224 | 226 | */ |
| 225 | - @Operation(summary = "分页查询子目录通道") | |
| 227 | + @Operation(summary = "分页查询子目录通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 226 | 228 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 227 | 229 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 228 | 230 | @Parameter(name = "page", description = "当前页", required = true) |
| ... | ... | @@ -254,7 +256,7 @@ public class DeviceQuery { |
| 254 | 256 | * @param channel 通道 |
| 255 | 257 | * @return |
| 256 | 258 | */ |
| 257 | - @Operation(summary = "更新通道信息") | |
| 259 | + @Operation(summary = "更新通道信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 258 | 260 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 259 | 261 | @Parameter(name = "channel", description = "通道信息", required = true) |
| 260 | 262 | @PostMapping("/channel/update/{deviceId}") |
| ... | ... | @@ -268,7 +270,7 @@ public class DeviceQuery { |
| 268 | 270 | * @param streamMode 数据流传输模式 |
| 269 | 271 | * @return |
| 270 | 272 | */ |
| 271 | - @Operation(summary = "修改数据流传输模式") | |
| 273 | + @Operation(summary = "修改数据流传输模式", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 272 | 274 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 273 | 275 | @Parameter(name = "streamMode", description = "数据流传输模式, 取值:" + |
| 274 | 276 | "UDP(udp传输),TCP-ACTIVE(tcp主动模式,暂不支持),TCP-PASSIVE(tcp被动模式)", required = true) |
| ... | ... | @@ -284,7 +286,7 @@ public class DeviceQuery { |
| 284 | 286 | * @param device 设备信息 |
| 285 | 287 | * @return |
| 286 | 288 | */ |
| 287 | - @Operation(summary = "添加设备信息") | |
| 289 | + @Operation(summary = "添加设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 288 | 290 | @Parameter(name = "device", description = "设备", required = true) |
| 289 | 291 | @PostMapping("/device/add/") |
| 290 | 292 | public void addDevice(Device device){ |
| ... | ... | @@ -306,7 +308,7 @@ public class DeviceQuery { |
| 306 | 308 | * @param device 设备信息 |
| 307 | 309 | * @return |
| 308 | 310 | */ |
| 309 | - @Operation(summary = "更新设备信息") | |
| 311 | + @Operation(summary = "更新设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 310 | 312 | @Parameter(name = "device", description = "设备", required = true) |
| 311 | 313 | @PostMapping("/device/update/") |
| 312 | 314 | public void updateDevice(Device device){ |
| ... | ... | @@ -321,7 +323,7 @@ public class DeviceQuery { |
| 321 | 323 | * |
| 322 | 324 | * @param deviceId 设备id |
| 323 | 325 | */ |
| 324 | - @Operation(summary = "设备状态查询") | |
| 326 | + @Operation(summary = "设备状态查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 325 | 327 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 326 | 328 | @GetMapping("/devices/{deviceId}/status") |
| 327 | 329 | public DeferredResult<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) { |
| ... | ... | @@ -372,7 +374,7 @@ public class DeviceQuery { |
| 372 | 374 | * @param endTime 报警发生终止时间(可选) |
| 373 | 375 | * @return true = 命令发送成功 |
| 374 | 376 | */ |
| 375 | - @Operation(summary = "设备状态查询") | |
| 377 | + @Operation(summary = "设备报警查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 376 | 378 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 377 | 379 | @Parameter(name = "startPriority", description = "报警起始级别") |
| 378 | 380 | @Parameter(name = "endPriority", description = "报警终止级别") |
| ... | ... | @@ -422,7 +424,7 @@ public class DeviceQuery { |
| 422 | 424 | |
| 423 | 425 | |
| 424 | 426 | @GetMapping("/{deviceId}/sync_status") |
| 425 | - @Operation(summary = "获取通道同步进度") | |
| 427 | + @Operation(summary = "获取通道同步进度", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 426 | 428 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 427 | 429 | public WVPResult<SyncStatus> getSyncStatus(@PathVariable String deviceId) { |
| 428 | 430 | SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId); |
| ... | ... | @@ -442,7 +444,7 @@ public class DeviceQuery { |
| 442 | 444 | } |
| 443 | 445 | |
| 444 | 446 | @GetMapping("/{deviceId}/subscribe_info") |
| 445 | - @Operation(summary = "获取设备的订阅状态") | |
| 447 | + @Operation(summary = "获取设备的订阅状态", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 446 | 448 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 447 | 449 | public WVPResult<Map<String, Integer>> getSubscribeInfo(@PathVariable String deviceId) { |
| 448 | 450 | Set<String> allKeys = dynamicTask.getAllKeys(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.gb28181.gbStream; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 4 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 4 | 5 | import com.genersoft.iot.vmp.gb28181.bean.GbStream; |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 6 | 7 | import com.genersoft.iot.vmp.service.IGbStreamService; |
| ... | ... | @@ -11,6 +12,7 @@ import com.genersoft.iot.vmp.vmanager.gb28181.gbStream.bean.GbStreamParam; |
| 11 | 12 | import com.github.pagehelper.PageInfo; |
| 12 | 13 | import io.swagger.v3.oas.annotations.Operation; |
| 13 | 14 | import io.swagger.v3.oas.annotations.Parameter; |
| 15 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 14 | 16 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 15 | 17 | import org.slf4j.Logger; |
| 16 | 18 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -43,7 +45,7 @@ public class GbStreamController { |
| 43 | 45 | * @param platformId 平台ID |
| 44 | 46 | * @return |
| 45 | 47 | */ |
| 46 | - @Operation(summary = "查询国标通道") | |
| 48 | + @Operation(summary = "查询国标通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 47 | 49 | @Parameter(name = "page", description = "当前页", required = true) |
| 48 | 50 | @Parameter(name = "count", description = "每页条数", required = true) |
| 49 | 51 | @Parameter(name = "platformId", description = "平台ID", required = true) |
| ... | ... | @@ -79,7 +81,7 @@ public class GbStreamController { |
| 79 | 81 | * @param gbStreamParam |
| 80 | 82 | * @return |
| 81 | 83 | */ |
| 82 | - @Operation(summary = "移除国标关联") | |
| 84 | + @Operation(summary = "移除国标关联", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 83 | 85 | @DeleteMapping(value = "/del") |
| 84 | 86 | @ResponseBody |
| 85 | 87 | public void del(@RequestBody GbStreamParam gbStreamParam){ |
| ... | ... | @@ -99,7 +101,7 @@ public class GbStreamController { |
| 99 | 101 | * @param gbStreamParam |
| 100 | 102 | * @return |
| 101 | 103 | */ |
| 102 | - @Operation(summary = "保存国标关联") | |
| 104 | + @Operation(summary = "保存国标关联", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 103 | 105 | @PostMapping(value = "/add") |
| 104 | 106 | @ResponseBody |
| 105 | 107 | public void add(@RequestBody GbStreamParam gbStreamParam){ |
| ... | ... | @@ -118,7 +120,7 @@ public class GbStreamController { |
| 118 | 120 | * @param gbId |
| 119 | 121 | * @return |
| 120 | 122 | */ |
| 121 | - @Operation(summary = "保存国标关联") | |
| 123 | + @Operation(summary = "保存国标关联", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 122 | 124 | @GetMapping(value = "/addWithGbid") |
| 123 | 125 | @ResponseBody |
| 124 | 126 | public void add(String gbId, String platformGbId, @RequestParam(required = false) String catalogGbId){ | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.media; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 5 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 5 | 6 | import com.genersoft.iot.vmp.conf.security.SecurityUtils; |
| 6 | 7 | import com.genersoft.iot.vmp.conf.security.dto.LoginUser; |
| 7 | 8 | import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; |
| ... | ... | @@ -12,6 +13,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 12 | 13 | import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 13 | 14 | import io.swagger.v3.oas.annotations.Operation; |
| 14 | 15 | import io.swagger.v3.oas.annotations.Parameter; |
| 16 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 15 | 17 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 16 | 18 | import org.slf4j.Logger; |
| 17 | 19 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -45,7 +47,7 @@ public class MediaController { |
| 45 | 47 | * @param stream 流id |
| 46 | 48 | * @return |
| 47 | 49 | */ |
| 48 | - @Operation(summary = "根据应用名和流id获取播放地址") | |
| 50 | + @Operation(summary = "根据应用名和流id获取播放地址", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 49 | 51 | @Parameter(name = "app", description = "应用名", required = true) |
| 50 | 52 | @Parameter(name = "stream", description = "流id", required = true) |
| 51 | 53 | @Parameter(name = "mediaServerId", description = "媒体服务器id") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
| ... | ... | @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 8 | 8 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 9 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 9 | 10 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform; |
| 10 | 11 | import com.genersoft.iot.vmp.gb28181.bean.ParentPlatformCatch; |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog; |
| ... | ... | @@ -21,6 +22,7 @@ import com.genersoft.iot.vmp.vmanager.gb28181.platform.bean.UpdateChannelParam; |
| 21 | 22 | import com.github.pagehelper.PageInfo; |
| 22 | 23 | import io.swagger.v3.oas.annotations.Operation; |
| 23 | 24 | import io.swagger.v3.oas.annotations.Parameter; |
| 25 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 24 | 26 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 25 | 27 | import org.slf4j.Logger; |
| 26 | 28 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -83,7 +85,7 @@ public class PlatformController { |
| 83 | 85 | * |
| 84 | 86 | * @return |
| 85 | 87 | */ |
| 86 | - @Operation(summary = "获取国标服务的配置") | |
| 88 | + @Operation(summary = "获取国标服务的配置", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 87 | 89 | @GetMapping("/server_config") |
| 88 | 90 | public JSONObject serverConfig() { |
| 89 | 91 | JSONObject result = new JSONObject(); |
| ... | ... | @@ -99,7 +101,7 @@ public class PlatformController { |
| 99 | 101 | * |
| 100 | 102 | * @return |
| 101 | 103 | */ |
| 102 | - @Operation(summary = "获取级联服务器信息") | |
| 104 | + @Operation(summary = "获取级联服务器信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 103 | 105 | @Parameter(name = "id", description = "平台国标编号", required = true) |
| 104 | 106 | @GetMapping("/info/{id}") |
| 105 | 107 | public ParentPlatform getPlatform(@PathVariable String id) { |
| ... | ... | @@ -119,7 +121,7 @@ public class PlatformController { |
| 119 | 121 | * @return |
| 120 | 122 | */ |
| 121 | 123 | @GetMapping("/query/{count}/{page}") |
| 122 | - @Operation(summary = "分页查询级联平台") | |
| 124 | + @Operation(summary = "分页查询级联平台", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 123 | 125 | @Parameter(name = "page", description = "当前页", required = true) |
| 124 | 126 | @Parameter(name = "count", description = "每页条数", required = true) |
| 125 | 127 | public PageInfo<ParentPlatform> platforms(@PathVariable int page, @PathVariable int count) { |
| ... | ... | @@ -140,7 +142,7 @@ public class PlatformController { |
| 140 | 142 | * @param parentPlatform |
| 141 | 143 | * @return |
| 142 | 144 | */ |
| 143 | - @Operation(summary = "添加上级平台信息") | |
| 145 | + @Operation(summary = "添加上级平台信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 144 | 146 | @PostMapping("/add") |
| 145 | 147 | @ResponseBody |
| 146 | 148 | public void addPlatform(@RequestBody ParentPlatform parentPlatform) { |
| ... | ... | @@ -185,7 +187,7 @@ public class PlatformController { |
| 185 | 187 | * @param parentPlatform |
| 186 | 188 | * @return |
| 187 | 189 | */ |
| 188 | - @Operation(summary = "保存上级平台信息") | |
| 190 | + @Operation(summary = "保存上级平台信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 189 | 191 | @PostMapping("/save") |
| 190 | 192 | @ResponseBody |
| 191 | 193 | public void savePlatform(@RequestBody ParentPlatform parentPlatform) { |
| ... | ... | @@ -216,7 +218,7 @@ public class PlatformController { |
| 216 | 218 | * @param serverGBId 上级平台国标ID |
| 217 | 219 | * @return |
| 218 | 220 | */ |
| 219 | - @Operation(summary = "删除上级平台") | |
| 221 | + @Operation(summary = "删除上级平台", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 220 | 222 | @Parameter(name = "serverGBId", description = "上级平台的国标编号") |
| 221 | 223 | @DeleteMapping("/delete/{serverGBId}") |
| 222 | 224 | @ResponseBody |
| ... | ... | @@ -273,7 +275,7 @@ public class PlatformController { |
| 273 | 275 | * @param serverGBId 上级平台国标ID |
| 274 | 276 | * @return |
| 275 | 277 | */ |
| 276 | - @Operation(summary = "查询上级平台是否存在") | |
| 278 | + @Operation(summary = "查询上级平台是否存在", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 277 | 279 | @Parameter(name = "serverGBId", description = "上级平台的国标编号") |
| 278 | 280 | @GetMapping("/exit/{serverGBId}") |
| 279 | 281 | @ResponseBody |
| ... | ... | @@ -294,7 +296,7 @@ public class PlatformController { |
| 294 | 296 | * @param channelType 通道类型 |
| 295 | 297 | * @return |
| 296 | 298 | */ |
| 297 | - @Operation(summary = "查询上级平台是否存在") | |
| 299 | + @Operation(summary = "查询上级平台是否存在", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 298 | 300 | @Parameter(name = "page", description = "当前页", required = true) |
| 299 | 301 | @Parameter(name = "count", description = "每页条数", required = true) |
| 300 | 302 | @Parameter(name = "platformId", description = "上级平台的国标编号") |
| ... | ... | @@ -331,7 +333,7 @@ public class PlatformController { |
| 331 | 333 | * @param param 通道关联参数 |
| 332 | 334 | * @return |
| 333 | 335 | */ |
| 334 | - @Operation(summary = "向上级平台添加国标通道") | |
| 336 | + @Operation(summary = "向上级平台添加国标通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 335 | 337 | @PostMapping("/update_channel_for_gb") |
| 336 | 338 | @ResponseBody |
| 337 | 339 | public void updateChannelForGB(@RequestBody UpdateChannelParam param) { |
| ... | ... | @@ -360,7 +362,7 @@ public class PlatformController { |
| 360 | 362 | * @param param 通道关联参数 |
| 361 | 363 | * @return |
| 362 | 364 | */ |
| 363 | - @Operation(summary = "从上级平台移除国标通道") | |
| 365 | + @Operation(summary = "从上级平台移除国标通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 364 | 366 | @DeleteMapping("/del_channel_for_gb") |
| 365 | 367 | @ResponseBody |
| 366 | 368 | public void delChannelForGB(@RequestBody UpdateChannelParam param) { |
| ... | ... | @@ -389,7 +391,7 @@ public class PlatformController { |
| 389 | 391 | * @param parentId 目录父ID |
| 390 | 392 | * @return |
| 391 | 393 | */ |
| 392 | - @Operation(summary = "获取目录") | |
| 394 | + @Operation(summary = "获取目录", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 393 | 395 | @Parameter(name = "platformId", description = "上级平台的国标编号", required = true) |
| 394 | 396 | @Parameter(name = "parentId", description = "父级目录的国标编号", required = true) |
| 395 | 397 | @GetMapping("/catalog") |
| ... | ... | @@ -420,7 +422,7 @@ public class PlatformController { |
| 420 | 422 | * @param platformCatalog 目录 |
| 421 | 423 | * @return |
| 422 | 424 | */ |
| 423 | - @Operation(summary = "添加目录") | |
| 425 | + @Operation(summary = "添加目录", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 424 | 426 | @PostMapping("/catalog/add") |
| 425 | 427 | @ResponseBody |
| 426 | 428 | public void addCatalog(@RequestBody PlatformCatalog platformCatalog) { |
| ... | ... | @@ -445,7 +447,7 @@ public class PlatformController { |
| 445 | 447 | * @param platformCatalog 目录 |
| 446 | 448 | * @return |
| 447 | 449 | */ |
| 448 | - @Operation(summary = "编辑目录") | |
| 450 | + @Operation(summary = "编辑目录", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 449 | 451 | @PostMapping("/catalog/edit") |
| 450 | 452 | @ResponseBody |
| 451 | 453 | public void editCatalog(@RequestBody PlatformCatalog platformCatalog) { |
| ... | ... | @@ -471,7 +473,7 @@ public class PlatformController { |
| 471 | 473 | * @param platformId 平台Id |
| 472 | 474 | * @return |
| 473 | 475 | */ |
| 474 | - @Operation(summary = "删除目录") | |
| 476 | + @Operation(summary = "删除目录", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 475 | 477 | @Parameter(name = "id", description = "目录Id", required = true) |
| 476 | 478 | @Parameter(name = "platformId", description = "平台Id", required = true) |
| 477 | 479 | @DeleteMapping("/catalog/del") |
| ... | ... | @@ -506,7 +508,7 @@ public class PlatformController { |
| 506 | 508 | * @param platformCatalog 关联的信息 |
| 507 | 509 | * @return |
| 508 | 510 | */ |
| 509 | - @Operation(summary = "删除关联") | |
| 511 | + @Operation(summary = "删除关联", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 510 | 512 | @DeleteMapping("/catalog/relation/del") |
| 511 | 513 | @ResponseBody |
| 512 | 514 | public void delRelation(@RequestBody PlatformCatalog platformCatalog) { |
| ... | ... | @@ -529,7 +531,7 @@ public class PlatformController { |
| 529 | 531 | * @param catalogId 目录Id |
| 530 | 532 | * @return |
| 531 | 533 | */ |
| 532 | - @Operation(summary = "修改默认目录") | |
| 534 | + @Operation(summary = "修改默认目录", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 533 | 535 | @Parameter(name = "catalogId", description = "目录Id", required = true) |
| 534 | 536 | @Parameter(name = "platformId", description = "平台Id", required = true) |
| 535 | 537 | @PostMapping("/catalog/default/update") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
| ... | ... | @@ -9,6 +9,7 @@ import com.genersoft.iot.vmp.common.StreamInfo; |
| 9 | 9 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 10 | 10 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 11 | 11 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 12 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 13 | 14 | import com.genersoft.iot.vmp.gb28181.bean.SsrcTransaction; |
| 14 | 15 | import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager; |
| ... | ... | @@ -31,6 +32,7 @@ import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 31 | 32 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 32 | 33 | import io.swagger.v3.oas.annotations.Operation; |
| 33 | 34 | import io.swagger.v3.oas.annotations.Parameter; |
| 35 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 34 | 36 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 35 | 37 | import org.slf4j.Logger; |
| 36 | 38 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -92,7 +94,7 @@ public class PlayController { |
| 92 | 94 | @Autowired |
| 93 | 95 | private UserSetting userSetting; |
| 94 | 96 | |
| 95 | - @Operation(summary = "开始点播") | |
| 97 | + @Operation(summary = "开始点播", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 96 | 98 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 97 | 99 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 98 | 100 | @GetMapping("/start/{deviceId}/{channelId}") |
| ... | ... | @@ -157,7 +159,7 @@ public class PlayController { |
| 157 | 159 | return result; |
| 158 | 160 | } |
| 159 | 161 | |
| 160 | - @Operation(summary = "停止点播") | |
| 162 | + @Operation(summary = "停止点播", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 161 | 163 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 162 | 164 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 163 | 165 | @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true) |
| ... | ... | @@ -202,7 +204,7 @@ public class PlayController { |
| 202 | 204 | * 将不是h264的视频通过ffmpeg 转码为h264 + aac |
| 203 | 205 | * @param streamId 流ID |
| 204 | 206 | */ |
| 205 | - @Operation(summary = "将不是h264的视频通过ffmpeg 转码为h264 + aac") | |
| 207 | + @Operation(summary = "将不是h264的视频通过ffmpeg 转码为h264 + aac", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 206 | 208 | @Parameter(name = "streamId", description = "视频流ID", required = true) |
| 207 | 209 | @PostMapping("/convert/{streamId}") |
| 208 | 210 | public JSONObject playConvert(@PathVariable String streamId) { |
| ... | ... | @@ -244,7 +246,7 @@ public class PlayController { |
| 244 | 246 | /** |
| 245 | 247 | * 结束转码 |
| 246 | 248 | */ |
| 247 | - @Operation(summary = "结束转码") | |
| 249 | + @Operation(summary = "结束转码", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 248 | 250 | @Parameter(name = "key", description = "视频流key", required = true) |
| 249 | 251 | @Parameter(name = "mediaServerId", description = "流媒体服务ID", required = true) |
| 250 | 252 | @PostMapping("/convertStop/{key}") |
| ... | ... | @@ -269,7 +271,7 @@ public class PlayController { |
| 269 | 271 | } |
| 270 | 272 | } |
| 271 | 273 | |
| 272 | - @Operation(summary = "语音广播命令") | |
| 274 | + @Operation(summary = "语音广播命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 273 | 275 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 274 | 276 | @Parameter(name = "deviceId", description = "通道国标编号", required = true) |
| 275 | 277 | @Parameter(name = "timeout", description = "推流超时时间(秒)", required = true) |
| ... | ... | @@ -309,7 +311,7 @@ public class PlayController { |
| 309 | 311 | playService.stopAudioBroadcast(deviceId, channelId); |
| 310 | 312 | } |
| 311 | 313 | |
| 312 | - @Operation(summary = "获取所有的ssrc") | |
| 314 | + @Operation(summary = "获取所有的ssrc", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 313 | 315 | @GetMapping("/ssrc") |
| 314 | 316 | public JSONObject getSSRC() { |
| 315 | 317 | if (logger.isDebugEnabled()) { |
| ... | ... | @@ -332,7 +334,7 @@ public class PlayController { |
| 332 | 334 | return jsonObject; |
| 333 | 335 | } |
| 334 | 336 | |
| 335 | - @Operation(summary = "获取截图") | |
| 337 | + @Operation(summary = "获取截图", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 336 | 338 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 337 | 339 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 338 | 340 | @Parameter(name = "isSubStream", description = "是否子码流(true-子码流,false-主码流),默认为false", required = true) | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
| ... | ... | @@ -7,6 +7,7 @@ import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 8 | 8 | import com.genersoft.iot.vmp.conf.exception.ServiceException; |
| 9 | 9 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 10 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 10 | 11 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 11 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 12 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| ... | ... | @@ -20,6 +21,7 @@ import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 20 | 21 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 21 | 22 | import io.swagger.v3.oas.annotations.Operation; |
| 22 | 23 | import io.swagger.v3.oas.annotations.Parameter; |
| 24 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 23 | 25 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 24 | 26 | import org.slf4j.Logger; |
| 25 | 27 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -68,7 +70,7 @@ public class PlaybackController { |
| 68 | 70 | @Autowired |
| 69 | 71 | private UserSetting userSetting; |
| 70 | 72 | |
| 71 | - @Operation(summary = "开始视频回放") | |
| 73 | + @Operation(summary = "开始视频回放", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 72 | 74 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 73 | 75 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 74 | 76 | @Parameter(name = "startTime", description = "开始时间", required = true) |
| ... | ... | @@ -125,7 +127,7 @@ public class PlaybackController { |
| 125 | 127 | } |
| 126 | 128 | |
| 127 | 129 | |
| 128 | - @Operation(summary = "停止视频回放") | |
| 130 | + @Operation(summary = "停止视频回放", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 129 | 131 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 130 | 132 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 131 | 133 | @Parameter(name = "stream", description = "流ID", required = true) |
| ... | ... | @@ -149,7 +151,7 @@ public class PlaybackController { |
| 149 | 151 | } |
| 150 | 152 | |
| 151 | 153 | |
| 152 | - @Operation(summary = "回放暂停") | |
| 154 | + @Operation(summary = "回放暂停", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 153 | 155 | @Parameter(name = "streamId", description = "回放流ID", required = true) |
| 154 | 156 | @GetMapping("/pause/{streamId}") |
| 155 | 157 | public void playPause(@PathVariable String streamId) { |
| ... | ... | @@ -165,7 +167,7 @@ public class PlaybackController { |
| 165 | 167 | } |
| 166 | 168 | |
| 167 | 169 | |
| 168 | - @Operation(summary = "回放恢复") | |
| 170 | + @Operation(summary = "回放恢复", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 169 | 171 | @Parameter(name = "streamId", description = "回放流ID", required = true) |
| 170 | 172 | @GetMapping("/resume/{streamId}") |
| 171 | 173 | public void playResume(@PathVariable String streamId) { |
| ... | ... | @@ -180,7 +182,7 @@ public class PlaybackController { |
| 180 | 182 | } |
| 181 | 183 | |
| 182 | 184 | |
| 183 | - @Operation(summary = "回放拖动播放") | |
| 185 | + @Operation(summary = "回放拖动播放", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 184 | 186 | @Parameter(name = "streamId", description = "回放流ID", required = true) |
| 185 | 187 | @Parameter(name = "seekTime", description = "拖动偏移量,单位s", required = true) |
| 186 | 188 | @GetMapping("/seek/{streamId}/{seekTime}") |
| ... | ... | @@ -200,7 +202,7 @@ public class PlaybackController { |
| 200 | 202 | } |
| 201 | 203 | } |
| 202 | 204 | |
| 203 | - @Operation(summary = "回放倍速播放") | |
| 205 | + @Operation(summary = "回放倍速播放", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 204 | 206 | @Parameter(name = "streamId", description = "回放流ID", required = true) |
| 205 | 207 | @Parameter(name = "speed", description = "倍速0.25 0.5 1、2、4", required = true) |
| 206 | 208 | @GetMapping("/speed/{streamId}/{speed}") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.ptz; |
| 2 | 2 | |
| 3 | 3 | |
| 4 | 4 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 5 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 5 | 6 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 6 | 7 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 7 | 8 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| ... | ... | @@ -10,6 +11,7 @@ import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 10 | 11 | import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 11 | 12 | import io.swagger.v3.oas.annotations.Operation; |
| 12 | 13 | import io.swagger.v3.oas.annotations.Parameter; |
| 14 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 13 | 15 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 14 | 16 | import org.slf4j.Logger; |
| 15 | 17 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -50,7 +52,7 @@ public class PtzController { |
| 50 | 52 | * @param zoomSpeed 缩放速度 |
| 51 | 53 | */ |
| 52 | 54 | |
| 53 | - @Operation(summary = "云台控制") | |
| 55 | + @Operation(summary = "云台控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 54 | 56 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 55 | 57 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 56 | 58 | @Parameter(name = "command", description = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", required = true) |
| ... | ... | @@ -113,7 +115,7 @@ public class PtzController { |
| 113 | 115 | } |
| 114 | 116 | |
| 115 | 117 | |
| 116 | - @Operation(summary = "通用前端控制命令") | |
| 118 | + @Operation(summary = "通用前端控制命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 117 | 119 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 118 | 120 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 119 | 121 | @Parameter(name = "cmdCode", description = "指令码", required = true) |
| ... | ... | @@ -137,7 +139,7 @@ public class PtzController { |
| 137 | 139 | } |
| 138 | 140 | |
| 139 | 141 | |
| 140 | - @Operation(summary = "预置位查询") | |
| 142 | + @Operation(summary = "预置位查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 141 | 143 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 142 | 144 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 143 | 145 | @GetMapping("/preset/query/{deviceId}/{channelId}") | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
| 1 | 1 | package com.genersoft.iot.vmp.vmanager.gb28181.record; |
| 2 | 2 | |
| 3 | +import com.genersoft.iot.vmp.common.InviteInfo; | |
| 4 | +import com.genersoft.iot.vmp.common.InviteSessionType; | |
| 3 | 5 | import com.genersoft.iot.vmp.common.StreamInfo; |
| 4 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 5 | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 6 | 8 | import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; |
| 9 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 7 | 10 | import com.genersoft.iot.vmp.gb28181.bean.Device; |
| 8 | 11 | import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; |
| 9 | 12 | import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; |
| 10 | 13 | import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; |
| 11 | 14 | import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; |
| 12 | 15 | import com.genersoft.iot.vmp.service.IDeviceService; |
| 16 | +import com.genersoft.iot.vmp.service.IInviteStreamService; | |
| 13 | 17 | import com.genersoft.iot.vmp.service.IPlayService; |
| 18 | +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; | |
| 14 | 19 | import com.genersoft.iot.vmp.service.bean.InviteErrorCode; |
| 15 | 20 | import com.genersoft.iot.vmp.storager.IVideoManagerStorage; |
| 16 | 21 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -19,10 +24,12 @@ import com.genersoft.iot.vmp.vmanager.bean.StreamContent; |
| 19 | 24 | import com.genersoft.iot.vmp.vmanager.bean.WVPResult; |
| 20 | 25 | import io.swagger.v3.oas.annotations.Operation; |
| 21 | 26 | import io.swagger.v3.oas.annotations.Parameter; |
| 27 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 22 | 28 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 23 | 29 | import org.slf4j.Logger; |
| 24 | 30 | import org.slf4j.LoggerFactory; |
| 25 | 31 | import org.springframework.beans.factory.annotation.Autowired; |
| 32 | +import org.springframework.util.ObjectUtils; | |
| 26 | 33 | import org.springframework.web.bind.annotation.GetMapping; |
| 27 | 34 | import org.springframework.web.bind.annotation.PathVariable; |
| 28 | 35 | import org.springframework.web.bind.annotation.RequestMapping; |
| ... | ... | @@ -56,12 +63,15 @@ public class GBRecordController { |
| 56 | 63 | private IPlayService playService; |
| 57 | 64 | |
| 58 | 65 | @Autowired |
| 66 | + private IInviteStreamService inviteStreamService; | |
| 67 | + | |
| 68 | + @Autowired | |
| 59 | 69 | private IDeviceService deviceService; |
| 60 | 70 | |
| 61 | 71 | @Autowired |
| 62 | 72 | private UserSetting userSetting; |
| 63 | 73 | |
| 64 | - @Operation(summary = "录像查询") | |
| 74 | + @Operation(summary = "录像查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 65 | 75 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 66 | 76 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 67 | 77 | @Parameter(name = "startTime", description = "开始时间", required = true) |
| ... | ... | @@ -115,7 +125,7 @@ public class GBRecordController { |
| 115 | 125 | } |
| 116 | 126 | |
| 117 | 127 | |
| 118 | - @Operation(summary = "开始历史媒体下载") | |
| 128 | + @Operation(summary = "开始历史媒体下载", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 119 | 129 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 120 | 130 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 121 | 131 | @Parameter(name = "startTime", description = "开始时间", required = true) |
| ... | ... | @@ -164,7 +174,7 @@ public class GBRecordController { |
| 164 | 174 | return result; |
| 165 | 175 | } |
| 166 | 176 | |
| 167 | - @Operation(summary = "停止历史媒体下载") | |
| 177 | + @Operation(summary = "停止历史媒体下载", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 168 | 178 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 169 | 179 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 170 | 180 | @Parameter(name = "stream", description = "流ID", required = true) |
| ... | ... | @@ -192,7 +202,7 @@ public class GBRecordController { |
| 192 | 202 | } |
| 193 | 203 | } |
| 194 | 204 | |
| 195 | - @Operation(summary = "获取历史媒体下载进度") | |
| 205 | + @Operation(summary = "获取历史媒体下载进度", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 196 | 206 | @Parameter(name = "deviceId", description = "设备国标编号", required = true) |
| 197 | 207 | @Parameter(name = "channelId", description = "通道国标编号", required = true) |
| 198 | 208 | @Parameter(name = "stream", description = "流ID", required = true) | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/log/LogController.java
| ... | ... | @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.vmanager.log; |
| 2 | 2 | |
| 3 | 3 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 4 | 4 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 5 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 5 | 6 | import com.genersoft.iot.vmp.service.ILogService; |
| 6 | 7 | import com.genersoft.iot.vmp.storager.dao.dto.LogDto; |
| 7 | 8 | import com.genersoft.iot.vmp.utils.DateUtil; |
| ... | ... | @@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 9 | 10 | import com.github.pagehelper.PageInfo; |
| 10 | 11 | import io.swagger.v3.oas.annotations.Operation; |
| 11 | 12 | import io.swagger.v3.oas.annotations.Parameter; |
| 13 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 12 | 14 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 13 | 15 | import org.slf4j.Logger; |
| 14 | 16 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -42,7 +44,7 @@ public class LogController { |
| 42 | 44 | * @return |
| 43 | 45 | */ |
| 44 | 46 | @GetMapping("/all") |
| 45 | - @Operation(summary = "分页查询日志") | |
| 47 | + @Operation(summary = "分页查询日志", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 46 | 48 | @Parameter(name = "query", description = "查询内容", required = true) |
| 47 | 49 | @Parameter(name = "page", description = "当前页", required = true) |
| 48 | 50 | @Parameter(name = "count", description = "每页查询数量", required = true) |
| ... | ... | @@ -84,7 +86,7 @@ public class LogController { |
| 84 | 86 | * 清空日志 |
| 85 | 87 | * |
| 86 | 88 | */ |
| 87 | - @Operation(summary = "清空日志") | |
| 89 | + @Operation(summary = "清空日志", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 88 | 90 | @DeleteMapping("/clear") |
| 89 | 91 | public void clear() { |
| 90 | 92 | logService.clear(); | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/ps/PsController.java
| ... | ... | @@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants; |
| 5 | 5 | import com.genersoft.iot.vmp.conf.DynamicTask; |
| 6 | 6 | import com.genersoft.iot.vmp.conf.UserSetting; |
| 7 | 7 | import com.genersoft.iot.vmp.conf.exception.ControllerException; |
| 8 | +import com.genersoft.iot.vmp.conf.security.JwtUtils; | |
| 8 | 9 | import com.genersoft.iot.vmp.media.zlm.SendRtpPortManager; |
| 9 | 10 | import com.genersoft.iot.vmp.media.zlm.ZLMServerFactory; |
| 10 | 11 | import com.genersoft.iot.vmp.media.zlm.ZlmHttpHookSubscribe; |
| ... | ... | @@ -19,6 +20,7 @@ import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; |
| 19 | 20 | import com.genersoft.iot.vmp.vmanager.bean.OtherPsSendInfo; |
| 20 | 21 | import io.swagger.v3.oas.annotations.Operation; |
| 21 | 22 | import io.swagger.v3.oas.annotations.Parameter; |
| 23 | +import io.swagger.v3.oas.annotations.security.SecurityRequirement; | |
| 22 | 24 | import io.swagger.v3.oas.annotations.tags.Tag; |
| 23 | 25 | import okhttp3.OkHttpClient; |
| 24 | 26 | import okhttp3.Request; |
| ... | ... | @@ -69,7 +71,7 @@ public class PsController { |
| 69 | 71 | |
| 70 | 72 | @GetMapping(value = "/receive/open") |
| 71 | 73 | @ResponseBody |
| 72 | - @Operation(summary = "开启收流和获取发流信息") | |
| 74 | + @Operation(summary = "开启收流和获取发流信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 73 | 75 | @Parameter(name = "isSend", description = "是否发送,false时只开启收流, true同时返回推流信息", required = true) |
| 74 | 76 | @Parameter(name = "callId", description = "整个过程的唯一标识,为了与后续接口关联", required = true) |
| 75 | 77 | @Parameter(name = "ssrc", description = "来源流的SSRC,不传则不校验来源ssrc", required = false) |
| ... | ... | @@ -152,7 +154,7 @@ public class PsController { |
| 152 | 154 | |
| 153 | 155 | @GetMapping(value = "/receive/close") |
| 154 | 156 | @ResponseBody |
| 155 | - @Operation(summary = "关闭收流") | |
| 157 | + @Operation(summary = "关闭收流", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 156 | 158 | @Parameter(name = "stream", description = "流的ID", required = true) |
| 157 | 159 | public void closeRtpServer(String stream) { |
| 158 | 160 | logger.info("[第三方PS服务对接->关闭收流] stream->{}", stream); |
| ... | ... | @@ -170,7 +172,7 @@ public class PsController { |
| 170 | 172 | |
| 171 | 173 | @GetMapping(value = "/send/start") |
| 172 | 174 | @ResponseBody |
| 173 | - @Operation(summary = "发送流") | |
| 175 | + @Operation(summary = "发送流", security = @SecurityRequirement(name = JwtUtils.HEADER)) | |
| 174 | 176 | @Parameter(name = "ssrc", description = "发送流的SSRC", required = true) |
| 175 | 177 | @Parameter(name = "dstIp", description = "目标收流IP", required = true) |
| 176 | 178 | @Parameter(name = "dstPort", description = "目标收流端口", required = true) | ... | ... |
src/main/java/com/genersoft/iot/vmp/vmanager/record/RecordController.java deleted
100755 → 0
| 1 | -//package com.genersoft.iot.vmp.vmanager.record; | |
| 2 | -// | |
| 3 | -//import com.alibaba.fastjson2.JSONObject; | |
| 4 | -//import com.genersoft.iot.vmp.media.zlm.dto.StreamPushItem; | |
| 5 | -//import com.genersoft.iot.vmp.service.IRecordInfoServer; | |
| 6 | -//import com.genersoft.iot.vmp.storager.dao.dto.RecordInfo; | |
| 7 | -//import com.genersoft.iot.vmp.vmanager.bean.WVPResult; | |
| 8 | -//import com.github.pagehelper.PageInfo; | |
| 9 | -//import io.swagger.annotations.Api; | |
| 10 | -//import io.swagger.annotations.ApiImplicitParam; | |
| 11 | -//import io.swagger.annotations.ApiImplicitParams; | |
| 12 | -//import io.swagger.annotations.ApiOperation; | |
| 13 | -//import org.springframework.beans.factory.annotation.Autowired; | |
| 14 | -//import org.springframework.web.bind.annotation.*; | |
| 15 | -// | |
| 16 | -//@Tag(name = "云端录像") | |
| 17 | -// | |
| 18 | -//@RestController | |
| 19 | -//@RequestMapping("/api/record") | |
| 20 | -//public class RecordController { | |
| 21 | -// | |
| 22 | -// @Autowired | |
| 23 | -// private IRecordInfoServer recordInfoServer; | |
| 24 | -// | |
| 25 | -// //@ApiOperation("录像列表查询") | |
| 26 | -// @ApiImplicitParams({ | |
| 27 | -// @ApiImplicitParam(name="page", value = "当前页", required = true, dataTypeClass = Integer.class), | |
| 28 | -// @ApiImplicitParam(name="count", value = "每页查询数量", required = true, dataTypeClass = Integer.class), | |
| 29 | -// @ApiImplicitParam(name="query", value = "查询内容", dataTypeClass = String.class), | |
| 30 | -// }) | |
| 31 | -// @GetMapping(value = "/app/list") | |
| 32 | -// @ResponseBody | |
| 33 | -// public Object list(@RequestParam(required = false)Integer page, | |
| 34 | -// @RequestParam(required = false)Integer count ){ | |
| 35 | -// | |
| 36 | -// PageInfo<RecordInfo> recordList = recordInfoServer.getRecordList(page - 1, page - 1 + count); | |
| 37 | -// return recordList; | |
| 38 | -// } | |
| 39 | -// | |
| 40 | -// //@ApiOperation("获取录像详情") | |
| 41 | -// @ApiImplicitParams({ | |
| 42 | -// @ApiImplicitParam(name="recordInfo", value = "录像记录", required = true, dataTypeClass = RecordInfo.class) | |
| 43 | -// }) | |
| 44 | -// @GetMapping(value = "/detail") | |
| 45 | -// @ResponseBody | |
| 46 | -// public JSONObject list(RecordInfo recordInfo, String time ){ | |
| 47 | -// | |
| 48 | -// | |
| 49 | -// return null; | |
| 50 | -// } | |
| 51 | -//} |