diff --git a/README.md b/README.md index 1116581f7..5afd26d43 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git # 功能特性 - [X] 集成web界面 - [X] 兼容性良好 +- [X] 跨平台服务,一次编译多端部署, 可以同时用于x86和arm架构 - [X] 接入设备 - [X] 视频预览 - [X] 支持主码流子码流切换 @@ -98,7 +99,7 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git - [X] 语音对讲 - [X] 支持同时级联到多个上级平台 - [X] 支持自动配置ZLM媒体服务, 减少因配置问题所出现的问题; -- [X] 多流媒体节点,自动选择负载最低的节点使用。 +- [X] 支持流媒体节点集群,负载均衡。 - [X] 支持启用udp多端口模式, 提高udp模式下媒体传输性能; - [X] 支持公网部署; - [X] 支持wvp与zlm分开部署,提升平台并发能力 @@ -113,10 +114,12 @@ https://gitee.com/pan648540858/wvp-GB28181-pro.git - [X] 支持录制计划, 根据设定的时间对通道进行录制. 暂不支持将录制的内容转发到国标上级 - [X] 支持Onvif, 目前付费提供, 永久免费试用包在知识星球获取 - [X] 支持国标28181-2022协议, 目前付费提供, 永久免费试用包在知识星球获取 +- [X] 支持国标信令集群 # 非开源的内容 - [X] ONVIF设备的接入,支持点播,云台控制,国标级联点播,自动点播。试用安装包以及使用教程: [知识星球](https://t.zsxq.com/10WAnH2MP),没有使用时间限制,需要源码可以星球私信我或者邮箱联系。 +- [X] 支持部标1078+808协议,支持点播,云台控制,录像回放,位置上报,自动点播。 - [X] 支持国标28181-2022协议,支持巡航轨迹查询,PTZ精准控制,存储卡格式化,设备软件升级,OSD配置,h265+aac,支持辅码流,录像倒放等。具体的功能列表可在[知识星球](https://t.zsxq.com/18GXkpkqs)查看,试用安装包: [知识星球](https://t.zsxq.com/UJ6V3),没有使用时间限制,需要源码可以星球私信我或者邮箱联系。 diff --git a/pom.xml b/pom.xml index 67e0b1a2c..07aa9d38f 100644 --- a/pom.xml +++ b/pom.xml @@ -199,13 +199,6 @@ springdoc-openapi-security 1.6.10 - - - com.baomidou - dynamic-datasource-spring-boot-starter - 3.6.1 - - diff --git a/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java b/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java index acd6092fd..9a7912d20 100644 --- a/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java +++ b/src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp; +import com.genersoft.iot.vmp.jt1078.util.ClassUtil; import com.genersoft.iot.vmp.utils.GitUtil; import com.genersoft.iot.vmp.utils.SpringBeanFactory; import lombok.extern.slf4j.Slf4j; @@ -33,6 +34,7 @@ public class VManageBootstrap extends SpringBootServletInitializer { public static void main(String[] args) { VManageBootstrap.args = args; VManageBootstrap.context = SpringApplication.run(VManageBootstrap.class, args); + ClassUtil.context = VManageBootstrap.context; GitUtil gitUtil = SpringBeanFactory.getBean("gitUtil"); if (gitUtil == null) { log.info("获取版本信息失败"); @@ -62,6 +64,5 @@ public class VManageBootstrap extends SpringBootServletInitializer { ); SessionCookieConfig sessionCookieConfig = servletContext.getSessionCookieConfig(); sessionCookieConfig.setHttpOnly(true); - } } diff --git a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java index adf9643fd..0c1279688 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/InviteInfo.java @@ -35,10 +35,16 @@ public class InviteInfo { private Long createTime; + private Boolean record; + + private String startTime; + + private String endTime; + public static InviteInfo getInviteInfo(String deviceId, Integer channelId, String stream, SSRCInfo ssrcInfo, String mediaServerId, String receiveIp, Integer receivePort, String streamMode, - InviteSessionType type, InviteSessionStatus status) { + InviteSessionType type, InviteSessionStatus status, Boolean record) { InviteInfo inviteInfo = new InviteInfo(); inviteInfo.setDeviceId(deviceId); inviteInfo.setChannelId(channelId); @@ -50,6 +56,7 @@ public class InviteInfo { inviteInfo.setType(type); inviteInfo.setStatus(status); inviteInfo.setMediaServerId(mediaServerId); + inviteInfo.setRecord(record); return inviteInfo; } diff --git a/src/main/java/com/genersoft/iot/vmp/common/ServerInfo.java b/src/main/java/com/genersoft/iot/vmp/common/ServerInfo.java new file mode 100644 index 000000000..fb1941a13 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/common/ServerInfo.java @@ -0,0 +1,23 @@ +package com.genersoft.iot.vmp.common; + +import com.genersoft.iot.vmp.utils.DateUtil; +import lombok.Data; + +@Data +public class ServerInfo { + + private String ip; + private int port; + /** + * 现在使用的线程数 + */ + private String createTime; + + public static ServerInfo create(String ip, int port) { + ServerInfo serverInfo = new ServerInfo(); + serverInfo.setIp(ip); + serverInfo.setPort(port); + serverInfo.setCreateTime(DateUtil.getNow()); + return serverInfo; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java index 280c11ba0..28e7d6416 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/common/StreamInfo.java @@ -4,11 +4,12 @@ import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; import java.io.Serializable; import java.util.Objects; - +@Data @Schema(description = "流信息") public class StreamInfo implements Serializable, Cloneable{ @@ -91,100 +92,15 @@ public class StreamInfo implements Serializable, Cloneable{ @Schema(description = "产生源类型,包括 unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7") private int originType; + @Schema(description = "originType的文本描述") + private String originTypeStr; + @Schema(description = "转码后的视频流") private StreamInfo transcodeStream; @Schema(description = "使用的WVP ID") private String serverId; - public void setFlv(StreamURL flv) { - this.flv = flv; - } - - public void setHttps_flv(StreamURL https_flv) { - this.https_flv = https_flv; - } - - public void setWs_flv(StreamURL ws_flv) { - this.ws_flv = ws_flv; - } - - public void setWss_flv(StreamURL wss_flv) { - this.wss_flv = wss_flv; - } - - public void setFmp4(StreamURL fmp4) { - this.fmp4 = fmp4; - } - - public void setHttps_fmp4(StreamURL https_fmp4) { - this.https_fmp4 = https_fmp4; - } - - public void setWs_fmp4(StreamURL ws_fmp4) { - this.ws_fmp4 = ws_fmp4; - } - - public void setWss_fmp4(StreamURL wss_fmp4) { - this.wss_fmp4 = wss_fmp4; - } - - public void setHls(StreamURL hls) { - this.hls = hls; - } - - public void setHttps_hls(StreamURL https_hls) { - this.https_hls = https_hls; - } - - public void setWs_hls(StreamURL ws_hls) { - this.ws_hls = ws_hls; - } - - public void setWss_hls(StreamURL wss_hls) { - this.wss_hls = wss_hls; - } - - public void setTs(StreamURL ts) { - this.ts = ts; - } - - public void setHttps_ts(StreamURL https_ts) { - this.https_ts = https_ts; - } - - public void setWs_ts(StreamURL ws_ts) { - this.ws_ts = ws_ts; - } - - public void setWss_ts(StreamURL wss_ts) { - this.wss_ts = wss_ts; - } - - public void setRtmp(StreamURL rtmp) { - this.rtmp = rtmp; - } - - public void setRtmps(StreamURL rtmps) { - this.rtmps = rtmps; - } - - public void setRtsp(StreamURL rtsp) { - this.rtsp = rtsp; - } - - public void setRtsps(StreamURL rtsps) { - this.rtsps = rtsps; - } - - public void setRtc(StreamURL rtc) { - this.rtc = rtc; - } - - public void setRtcs(StreamURL rtcs) { - this.rtcs = rtcs; - } - public void setRtmp(String host, int port, int sslPort, String app, String stream, String callIdParam) { String file = String.format("%s/%s%s", app, stream, callIdParam); if (port > 0) { @@ -275,7 +191,7 @@ public class StreamInfo implements Serializable, Cloneable{ } } - public void channgeStreamIp(String localAddr) { + public void changeStreamIp(String localAddr) { if (this.flv != null) { this.flv.setHost(localAddr); } @@ -351,205 +267,6 @@ public class StreamInfo implements Serializable, Cloneable{ private TransactionInfo transactionInfo; - public String getApp() { - return app; - } - - public void setApp(String app) { - this.app = app; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public Integer getChannelId() { - return channelId; - } - - public void setChannelId(Integer channelId) { - this.channelId = channelId; - } - - public String getStream() { - return stream; - } - - public void setStream(String stream) { - this.stream = stream; - } - - public String getIp() { - return ip; - } - - public void setIp(String ip) { - this.ip = ip; - } - - public StreamURL getFlv() { - return flv; - } - - public StreamURL getHttps_flv() { - return https_flv; - } - - public StreamURL getWs_flv() { - return ws_flv; - } - - - public StreamURL getWss_flv() { - return wss_flv; - } - - public StreamURL getFmp4() { - return fmp4; - } - - - - public StreamURL getHttps_fmp4() { - return https_fmp4; - } - - public StreamURL getWs_fmp4() { - return ws_fmp4; - } - - public StreamURL getWss_fmp4() { - return wss_fmp4; - } - - public StreamURL getHls() { - return hls; - } - - - public StreamURL getHttps_hls() { - return https_hls; - } - - public StreamURL getWs_hls() { - return ws_hls; - } - - public StreamURL getWss_hls() { - return wss_hls; - } - - public StreamURL getTs() { - return ts; - } - - - public StreamURL getHttps_ts() { - return https_ts; - } - - - public StreamURL getWs_ts() { - return ws_ts; - } - - - public StreamURL getWss_ts() { - return wss_ts; - } - - - public StreamURL getRtmp() { - return rtmp; - } - - public StreamURL getRtmps() { - return rtmps; - } - - public StreamURL getRtsp() { - return rtsp; - } - - public StreamURL getRtsps() { - return rtsps; - } - - public StreamURL getRtc() { - return rtc; - } - - public StreamURL getRtcs() { - return rtcs; - } - - public MediaServer getMediaServer() { - return mediaServer; - } - - public void setMediaServer(MediaServer mediaServer) { - this.mediaServer = mediaServer; - } - - public MediaInfo getMediaInfo() { - return mediaInfo; - } - - public void setMediaInfo(MediaInfo mediaInfo) { - this.mediaInfo = mediaInfo; - } - - public String getStartTime() { - return startTime; - } - - public void setStartTime(String startTime) { - this.startTime = startTime; - } - - public String getEndTime() { - return endTime; - } - - public void setEndTime(String endTime) { - this.endTime = endTime; - } - - public double getProgress() { - return progress; - } - - public void setProgress(double progress) { - this.progress = progress; - } - - public boolean isPause() { - return pause; - } - - public void setPause(boolean pause) { - this.pause = pause; - } - - public TransactionInfo getTransactionInfo() { - return transactionInfo; - } - - public void setTransactionInfo(TransactionInfo transactionInfo) { - this.transactionInfo = transactionInfo; - } - - public StreamInfo getTranscodeStream() { - return transcodeStream; - } - - public void setTranscodeStream(StreamInfo transcodeStream) { - this.transcodeStream = transcodeStream; - } @Override public StreamInfo clone() { @@ -625,48 +342,4 @@ public class StreamInfo implements Serializable, Cloneable{ return instance; } - - /*=========================设备主子码流逻辑START====================*/ - @Schema(description = "是否为子码流(true-是,false-主码流)") - private boolean subStream; - - public boolean isSubStream() { - return subStream; - } - - public void setSubStream(boolean subStream) { - this.subStream = subStream; - } - - public DownloadFileInfo getDownLoadFilePath() { - return downLoadFilePath; - } - - public void setDownLoadFilePath(DownloadFileInfo downLoadFilePath) { - this.downLoadFilePath = downLoadFilePath; - } - - public int getOriginType() { - return originType; - } - - public void setOriginType(int originType) { - this.originType = originType; - } - - public String getServerId() { - return serverId; - } - - public void setServerId(String serverId) { - this.serverId = serverId; - } - - public String getCallId() { - return callId; - } - - public void setCallId(String callId) { - this.callId = callId; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java index 442709918..f498ba51b 100644 --- a/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java +++ b/src/main/java/com/genersoft/iot/vmp/common/VideoManagerConstants.java @@ -10,6 +10,8 @@ public class VideoManagerConstants { public static final String WVP_SERVER_PREFIX = "VMP_SIGNALLING_SERVER_INFO_"; + public static final String WVP_SERVER_LIST = "VMP_SERVER_LIST"; + public static final String WVP_SERVER_STREAM_PREFIX = "VMP_SIGNALLING_STREAM_"; public static final String MEDIA_SERVER_PREFIX = "VMP_MEDIA_SERVER_INFO:"; diff --git a/src/main/java/com/genersoft/iot/vmp/common/enums/ChannelDataType.java b/src/main/java/com/genersoft/iot/vmp/common/enums/ChannelDataType.java new file mode 100644 index 000000000..c2d2a11e0 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/common/enums/ChannelDataType.java @@ -0,0 +1,21 @@ +package com.genersoft.iot.vmp.common.enums; + +/** + * 支持的通道数据类型 + */ + +public enum ChannelDataType { + + GB28181(1,"国标28181"), + STREAM_PUSH(2,"推流设备"), + STREAM_PROXY(3,"拉流代理"); + + public final int value; + + public final String desc; + + ChannelDataType(Integer value, String desc) { + this.value = value; + this.desc = desc; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java index 4742daa55..67c926e61 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipConfig.java @@ -6,6 +6,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import java.util.List; + @Component @ConfigurationProperties(prefix = "sip", ignoreInvalidFields = true) @Order(0) @@ -16,6 +18,8 @@ public class SipConfig { private String showIp; + private List monitorIps; + private Integer port; private String domain; @@ -30,5 +34,5 @@ public class SipConfig { private boolean alarm = false; - private long timeout = 15; + private long timeout = 150; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java b/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java index e6a9006a0..cb12754e6 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/SipPlatformRunner.java @@ -31,10 +31,13 @@ public class SipPlatformRunner implements CommandLineRunner { @Autowired private ISIPCommanderForPlatform sipCommanderForPlatform; + @Autowired + private UserSetting userSetting; + @Override public void run(String... args) throws Exception { // 获取所有启用的平台 - List parentPlatforms = platformService.queryEnablePlatformList(); + List parentPlatforms = platformService.queryEnablePlatformList(userSetting.getServerId()); for (Platform platform : parentPlatforms) { diff --git a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java index c64b4ba88..ca346dfab 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java @@ -37,6 +37,11 @@ public class UserSetting { */ private Integer playTimeout = 10000; + /** + * 获取设备录像数据超时时间,单位:毫秒 + */ + private Integer recordInfoTimeout = 15000; + /** * 上级点播等待超时时间,单位:毫秒 */ @@ -175,4 +180,15 @@ public class UserSetting { */ private long loginTimeout = 30; + /** + * jwk文件路径,若不指定则使用resources目录下的jwk.json + */ + private String jwkFile = "classpath:jwk.json"; + + /** + * wvp集群模式下如果注册向上级的wvp奔溃,则自动选择一个其他wvp继续注册到上级 + */ + private boolean autoRegisterPlatform = false; + + } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java b/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java index 6da0caf3a..4a2098a27 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/WVPTimerTask.java @@ -1,12 +1,14 @@ package com.genersoft.iot.vmp.conf; -import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.ServerInfo; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import java.util.concurrent.TimeUnit; + @Component public class WVPTimerTask { @@ -19,11 +21,8 @@ public class WVPTimerTask { @Autowired private SipConfig sipConfig; - @Scheduled(fixedDelay = 2 * 1000) //每3秒执行一次 + @Scheduled(fixedDelay = 2, timeUnit = TimeUnit.SECONDS) //每3秒执行一次 public void execute(){ - JSONObject jsonObject = new JSONObject(); - jsonObject.put("ip", sipConfig.getShowIp()); - jsonObject.put("port", serverPort); - redisCatchStorage.updateWVPInfo(jsonObject, 3); + redisCatchStorage.updateWVPInfo(ServerInfo.create(sipConfig.getShowIp(), serverPort), 3); } } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java index b762838c6..b541f7448 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/redis/RedisRpcConfig.java @@ -3,10 +3,12 @@ package com.genersoft.iot.vmp.conf.redis; import com.alibaba.fastjson2.JSON; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcClassHandler; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; -import com.genersoft.iot.vmp.service.redisMsg.control.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -16,8 +18,10 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; +import javax.sip.message.Response; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.HashMap; import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; @@ -36,9 +40,6 @@ public class RedisRpcConfig implements MessageListener { @Autowired private UserSetting userSetting; - @Autowired - private RedisRpcController redisRpcController; - @Autowired private RedisTemplate redisTemplate; @@ -48,6 +49,40 @@ public class RedisRpcConfig implements MessageListener { @Autowired private ThreadPoolTaskExecutor taskExecutor; + private final static Map protocolHash = new HashMap<>(); + + public void addHandler(String path, RedisRpcClassHandler handler) { + protocolHash.put(path, handler); + } + +// @Override +// public void run(String... args) throws Exception { +// List> classList = ClassUtil.getClassList("com.genersoft.iot.vmp.service.redisMsg.control", RedisRpcController.class); +// for (Class handlerClass : classList) { +// String controllerPath = handlerClass.getAnnotation(RedisRpcController.class).value(); +// Object bean = ClassUtil.getBean(controllerPath, handlerClass); +// // 扫描其下的方法 +// Method[] methods = handlerClass.getDeclaredMethods(); +// for (Method method : methods) { +// RedisRpcMapping annotation = method.getAnnotation(RedisRpcMapping.class); +// if (annotation != null) { +// String methodPath = annotation.value(); +// if (methodPath != null) { +// protocolHash.put(controllerPath + "/" + methodPath, new RedisRpcClassHandler(bean, method)); +// } +// } +// +// } +// +// } +// for (String s : protocolHash.keySet()) { +// System.out.println(s); +// } +// if (log.isDebugEnabled()) { +// log.debug("消息ID缓存表 protocolHash:{}", protocolHash); +// } +// } + @Override public void onMessage(Message message, byte[] pattern) { boolean isEmpty = taskQueue.isEmpty(); @@ -63,10 +98,10 @@ public class RedisRpcConfig implements MessageListener { } else if (redisRpcMessage.getResponse() != null){ handlerResponse(redisRpcMessage.getResponse()); } else { - log.error("[redis rpc 解析失败] {}", JSON.toJSONString(redisRpcMessage)); + log.error("[redis-rpc]解析失败 {}", JSON.toJSONString(redisRpcMessage)); } } catch (Exception e) { - log.error("[redis rpc 解析异常] ", e); + log.error("[redis-rpc]解析异常 {}",new String(msg.getBody()), e); } } }); @@ -87,17 +122,23 @@ public class RedisRpcConfig implements MessageListener { return; } log.info("[redis-rpc] << {}", request); - Method method = getMethod(request.getUri()); + RedisRpcClassHandler redisRpcClassHandler = protocolHash.get(request.getUri()); + if (redisRpcClassHandler == null) { + log.error("[redis-rpc] 路径: {}不存在", request.getUri()); + return; + } + RpcController controller = redisRpcClassHandler.getController(); + Method method = redisRpcClassHandler.getMethod(); // 没有携带目标ID的可以理解为哪个wvp有结果就哪个回复,携带目标ID,但是如果是不存在的uri则直接回复404 if (userSetting.getServerId().equals(request.getToId())) { if (method == null) { // 回复404结果 RedisRpcResponse response = request.getResponse(); - response.setStatusCode(404); + response.setStatusCode(ErrorCode.ERROR404.getCode()); sendResponse(response); return; } - RedisRpcResponse response = (RedisRpcResponse)method.invoke(redisRpcController, request); + RedisRpcResponse response = (RedisRpcResponse)method.invoke(controller, request); if(response != null) { sendResponse(response); } @@ -105,26 +146,14 @@ public class RedisRpcConfig implements MessageListener { if (method == null) { return; } - RedisRpcResponse response = (RedisRpcResponse)method.invoke(redisRpcController, request); + RedisRpcResponse response = (RedisRpcResponse)method.invoke(controller, request); if (response != null) { sendResponse(response); } } }catch (InvocationTargetException | IllegalAccessException e) { - log.error("[redis rpc ] 处理请求失败 ", e); + log.error("[redis-rpc ] 处理请求失败 ", e); } - - } - - private Method getMethod(String name) { - // 启动后扫描所有的路径注解 - Method[] methods = redisRpcController.getClass().getMethods(); - for (Method method : methods) { - if (method.getName().equals(name)) { - return method; - } - } - return null; } private void sendResponse(RedisRpcResponse response){ @@ -142,23 +171,28 @@ public class RedisRpcConfig implements MessageListener { redisTemplate.convertAndSend(REDIS_REQUEST_CHANNEL_KEY, message); } - private final Map> topicSubscribers = new ConcurrentHashMap<>(); private final Map> callbacks = new ConcurrentHashMap<>(); - public RedisRpcResponse request(RedisRpcRequest request, int timeOut) { + public RedisRpcResponse request(RedisRpcRequest request, long timeOut) { + return request(request, timeOut, TimeUnit.SECONDS); + } + + public RedisRpcResponse request(RedisRpcRequest request, long timeOut, TimeUnit timeUnit) { request.setSn((long) random.nextInt(1000) + 1); SynchronousQueue subscribe = subscribe(request.getSn()); try { sendRequest(request); - return subscribe.poll(timeOut, TimeUnit.SECONDS); + return subscribe.poll(timeOut, timeUnit); } catch (InterruptedException e) { log.warn("[redis rpc timeout] uri: {}, sn: {}", request.getUri(), request.getSn(), e); + RedisRpcResponse redisRpcResponse = new RedisRpcResponse(); + redisRpcResponse.setStatusCode(ErrorCode.ERROR486.getCode()); + return redisRpcResponse; } finally { this.unsubscribe(request.getSn()); } - return null; } public void request(RedisRpcRequest request, CommonCallback callback) { @@ -209,6 +243,9 @@ public class RedisRpcConfig implements MessageListener { return callbacks.size(); } + + + // @Scheduled(fixedRate = 1000) //每1秒执行一次 // public void execute(){ // logger.info("callbacks的长度: " + callbacks.size()); diff --git a/src/main/java/com/genersoft/iot/vmp/conf/redis/bean/RedisRpcClassHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/redis/bean/RedisRpcClassHandler.java new file mode 100644 index 000000000..1fab24bbe --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/conf/redis/bean/RedisRpcClassHandler.java @@ -0,0 +1,18 @@ +package com.genersoft.iot.vmp.conf.redis.bean; + +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import lombok.Data; + +import java.lang.reflect.Method; + +@Data +public class RedisRpcClassHandler { + + private RpcController controller; + private Method method; + + public RedisRpcClassHandler(RpcController controller, Method method) { + this.controller = controller; + this.method = method; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java index 61e019c60..37a3307e5 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java @@ -21,12 +21,16 @@ import org.jose4j.jwt.consumer.JwtConsumer; import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.jose4j.lang.JoseException; import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.io.BufferedReader; +import java.io.File; +import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.List; @@ -92,8 +96,46 @@ public class JwtUtils implements InitializingBean { */ private RsaJsonWebKey generateRsaJsonWebKey() throws JoseException { RsaJsonWebKey rsaJsonWebKey = null; - try (BufferedReader reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("/jwk.json"), StandardCharsets.UTF_8))) { - String jwkJson = reader.readLine(); + try { + String jwkFile = userSetting.getJwkFile(); + InputStream inputStream = null; + if (jwkFile.startsWith("classpath:")){ + String filePath = jwkFile.substring("classpath:".length()); + ClassPathResource civilCodeFile = new ClassPathResource(filePath); + if (civilCodeFile.exists()) { + inputStream = civilCodeFile.getInputStream(); + } + }else { + File civilCodeFile = new File(userSetting.getCivilCodeFile()); + if (civilCodeFile.exists()) { + inputStream = Files.newInputStream(civilCodeFile.toPath()); + } + + } + if (inputStream == null ) { + log.warn("[API AUTH] 读取jwk.json失败,文件不存在,将使用新生成的随机RSA密钥对"); + // 生成一个RSA密钥对,该密钥对将用于JWT的签名和验证,包装在JWK中 + rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); + // 给JWK一个密钥ID + rsaJsonWebKey.setKeyId(keyId); + return rsaJsonWebKey; + } + BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + int index = -1; + String line; + StringBuilder content = new StringBuilder(); + while ((line = inputStreamReader.readLine()) != null) { + content.append(line); + index ++; + if (index == 0) { + continue; + } + } + inputStreamReader.close(); + inputStream.close(); + + + String jwkJson = content.toString(); JsonWebKeySet jsonWebKeySet = new JsonWebKeySet(jwkJson); List jsonWebKeys = jsonWebKeySet.getJsonWebKeys(); if (!jsonWebKeys.isEmpty()) { @@ -102,14 +144,15 @@ public class JwtUtils implements InitializingBean { rsaJsonWebKey = (RsaJsonWebKey) jsonWebKey; } } - } catch (Exception e) { - // ignored - } + } catch (Exception ignore) {} if (rsaJsonWebKey == null) { + log.warn("[API AUTH] 读取jwk.json失败,获取内容失败,将使用新生成的随机RSA密钥对"); // 生成一个RSA密钥对,该密钥对将用于JWT的签名和验证,包装在JWK中 rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048); // 给JWK一个密钥ID rsaJsonWebKey.setKeyId(keyId); + }else { + log.info("[API AUTH] 读取jwk.json成功"); } return rsaJsonWebKey; } diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java index 2bdad1ff3..7c4680146 100644 --- a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java @@ -148,8 +148,10 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter { corsConfiguration.setAllowCredentials(true); corsConfiguration.setAllowedOrigins(userSetting.getAllowedOrigins()); }else { - corsConfiguration.setAllowCredentials(false); - corsConfiguration.setAllowedOrigins(Collections.singletonList(CorsConfiguration.ALL)); + // 在SpringBoot 2.4及以上版本处理跨域时,遇到错误提示:当allowCredentials为true时,allowedOrigins不能包含特殊值"*"。 + // 解决方法是明确指定allowedOrigins或使用allowedOriginPatterns。 + corsConfiguration.setAllowCredentials(true); + corsConfiguration.addAllowedOriginPattern(CorsConfiguration.ALL); // 默认全部允许所有跨域 } corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader())); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java index cbbb29596..78351bc2f 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/SipLayer.java @@ -80,11 +80,12 @@ public class SipLayer implements CommandLineRunner { monitorIps.add(sipConfig.getIp()); } } + sipConfig.setMonitorIps(monitorIps); if (ObjectUtils.isEmpty(sipConfig.getShowIp())){ sipConfig.setShowIp(String.join(",", monitorIps)); } SipFactory.getInstance().setPathName("gov.nist"); - if (monitorIps.size() > 0) { + if (!monitorIps.isEmpty()) { for (String monitorIp : monitorIps) { addListeningPoint(monitorIp, sipConfig.getPort()); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java index 2de1e913c..f4617b891 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/auth/DigestServerAuthenticationHelper.java @@ -156,8 +156,17 @@ public class DigestServerAuthenticationHelper { } /** - * Authenticate the inbound request given plain text password. + * 鉴权 * + * A1 = username + ":" + realm + ":" + password + * A2 = REGISTER:URI + * + * HA1 = md5(A1) + * HA2 = md5(A2) + * + * KD = HA2:HA2:qop + * + * response = md5(KD) * @param request - the request to authenticate. * @param pass -- the plain text password. * diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/BasicParam.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/BasicParam.java new file mode 100644 index 000000000..1ec7a721f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/BasicParam.java @@ -0,0 +1,49 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 基础配置 + */ +@Data +@Schema(description = "基础配置") +public class BasicParam { + + @Schema(description = "设备ID") + private String deviceId; + + @Schema(description = "通道ID,如果时对设备配置直接设置同设备ID一样即可") + private String channelId; + + @Schema(description = "名称") + private String name; + + @Schema(description = "注册过期时间") + private String expiration; + + @Schema(description = "心跳间隔时间") + private Integer heartBeatInterval; + + @Schema(description = "心跳超时次数") + private Integer heartBeatCount; + + @Schema(description = "定位功能支持情况。取值:0-不支持;1-支持 GPS定位;2-支持北斗定位(可选,默认取值为0)," + + "用于接受配置查询结果, 基础配置时无效") + private Integer positionCapability; + + @Schema(description = "经度(可选),用于接受配置查询结果, 基础配置时无效") + private Double longitude; + + @Schema(description = "纬度(可选),用于接受配置查询结果, 基础配置时无效") + private Double latitude; + + public static BasicParam getInstance(String name, String expiration, Integer heartBeatInterval, Integer heartBeatCount) { + BasicParam basicParam = new BasicParam(); + basicParam.setName(name); + basicParam.setExpiration(expiration); + basicParam.setHeartBeatInterval(heartBeatInterval); + basicParam.setHeartBeatCount(heartBeatCount); + return basicParam; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java index b9f37906e..a4179c1d1 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/CommonGBChannel.java @@ -123,17 +123,14 @@ public class CommonGBChannel { @Schema(description = "国标-时域编码能力,取值0-不支持;1-1级增强;2-2级增强;3-3级增强(可选)") private Integer gbSvcTimeSupportMode; - @Schema(description = "关联的国标设备数据库ID") - private Integer gbDeviceDbId; - @Schema(description = "二进制保存的录制计划, 每一位表示每个小时的前半个小时") private Long recordPLan; - @Schema(description = "关联的推流Id(流来源是推流时有效)") - private Integer streamPushId; + @Schema(description = "关联的数据类型") + private Integer dataType; - @Schema(description = "关联的拉流代理Id(流来源是拉流代理时有效)") - private Integer streamProxyId; + @Schema(description = "关联的设备ID") + private Integer dataDeviceId; @Schema(description = "关联的部标标通道ID") private Integer jtChannelId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java index 1e783e867..aa4bd0a69 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java @@ -104,7 +104,21 @@ public class Device { * 心跳间隔 */ @Schema(description = "心跳间隔") - private int keepaliveIntervalTime; + private Integer heartBeatInterval; + + + /** + * 心跳超时次数 + */ + @Schema(description = "心跳超时次数") + private Integer heartBeatCount; + + + /** + * 定位功能支持情况 + */ + @Schema(description = "定位功能支持情况。取值:0-不支持;1-支持 GPS定位;2-支持北斗定位(可选,默认取值为0") + private Integer positionCapability; /** * 通道个数 @@ -195,4 +209,7 @@ public class Device { @Schema(description = "控制语音对讲流程,释放收到ACK后发流") private boolean broadcastPushAfterAck; + + @Schema(description = "所属服务Id") + private String serverId; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java index 28eb01a8e..ab35ac51a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DeviceChannel.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.bean; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.utils.MessageElementForCatalog; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; import io.swagger.v3.oas.annotations.media.Schema; @@ -20,9 +21,6 @@ public class DeviceChannel extends CommonGBChannel { @Schema(description = "数据库自增ID") private int id; - @Schema(description = "设备的数据库自增ID") - private Integer deviceDbId; - @MessageElementForCatalog("DeviceID") @Schema(description = "编码") private String deviceId; @@ -191,6 +189,8 @@ public class DeviceChannel extends CommonGBChannel { @Schema(description = "通道类型, 默认0, 0: 普通通道,1 行政区划 2 业务分组/虚拟组织") private int channelType; + private Integer dataType = ChannelDataType.GB28181.value; + public void setPtzType(int ptzType) { this.ptzType = ptzType; switch (ptzType) { @@ -244,5 +244,15 @@ public class DeviceChannel extends CommonGBChannel { return deviceChannel; } + public CommonGBChannel buildCommonGBChannelForStatus() { + CommonGBChannel commonGBChannel = new CommonGBChannel(); + commonGBChannel.setGbId(id); + commonGBChannel.setGbDeviceId(deviceId); + commonGBChannel.setGbName(name); + commonGBChannel.setDataType(ChannelDataType.GB28181.value); + commonGBChannel.setDataDeviceId(getDataDeviceId()); + return commonGBChannel; + } + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomParam.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomParam.java new file mode 100644 index 000000000..d9b3a81d6 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomParam.java @@ -0,0 +1,34 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import com.genersoft.iot.vmp.gb28181.utils.MessageElement; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "拉框放大/缩小控制参数") +public class DragZoomParam { + + @MessageElement("Length") + @Schema(description = "播放窗口长度像素值(必选)") + protected Integer length; + + @MessageElement("Width") + @Schema(description = "播放窗口宽度像素值(必选)") + protected Integer width; + + @MessageElement("MidPointX") + @Schema(description = "拉框中心的横轴坐标像素值(必选)") + protected Integer midPointX; + + @MessageElement("MidPointY") + @Schema(description = "拉框中心的纵轴坐标像素值(必选)") + protected Integer midPointY; + + @MessageElement("LengthX") + @Schema(description = "拉框长度像素值(必选)") + protected Integer lengthX; + + @MessageElement("LengthY") + @Schema(description = "拉框宽度像素值(必选)") + protected Integer lengthY; +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java index 86fdb4d29..1a58c10fd 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/DragZoomRequest.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.bean; import com.genersoft.iot.vmp.gb28181.utils.MessageElement; +import lombok.Data; /** * 设备信息查询响应 @@ -9,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.utils.MessageElement; * @version 1.0 * @date 2022/6/28 14:55 */ +@Data public class DragZoomRequest { /** * 序列号 @@ -20,124 +22,9 @@ public class DragZoomRequest { private String deviceId; @MessageElement(value = "DragZoomIn") - private DragZoom dragZoomIn; + private DragZoomParam dragZoomIn; @MessageElement(value = "DragZoomOut") - private DragZoom dragZoomOut; + private DragZoomParam dragZoomOut; - /** - * 基本参数 - */ - public static class DragZoom { - /** - * 播放窗口长度像素值 - */ - @MessageElement("Length") - protected Integer length; - /** - * 播放窗口宽度像素值 - */ - @MessageElement("Width") - protected Integer width; - /** - * 拉框中心的横轴坐标像素值 - */ - @MessageElement("MidPointX") - protected Integer midPointX; - /** - * 拉框中心的纵轴坐标像素值 - */ - @MessageElement("MidPointY") - protected Integer midPointY; - /** - * 拉框长度像素值 - */ - @MessageElement("LengthX") - protected Integer lengthX; - /** - * 拉框宽度像素值 - */ - @MessageElement("LengthY") - protected Integer lengthY; - - public Integer getLength() { - return length; - } - - public void setLength(Integer length) { - this.length = length; - } - - public Integer getWidth() { - return width; - } - - public void setWidth(Integer width) { - this.width = width; - } - - public Integer getMidPointX() { - return midPointX; - } - - public void setMidPointX(Integer midPointX) { - this.midPointX = midPointX; - } - - public Integer getMidPointY() { - return midPointY; - } - - public void setMidPointY(Integer midPointY) { - this.midPointY = midPointY; - } - - public Integer getLengthX() { - return lengthX; - } - - public void setLengthX(Integer lengthX) { - this.lengthX = lengthX; - } - - public Integer getLengthY() { - return lengthY; - } - - public void setLengthY(Integer lengthY) { - this.lengthY = lengthY; - } - } - - public String getSn() { - return sn; - } - - public void setSn(String sn) { - this.sn = sn; - } - - public String getDeviceId() { - return deviceId; - } - - public void setDeviceId(String deviceId) { - this.deviceId = deviceId; - } - - public DragZoom getDragZoomIn() { - return dragZoomIn; - } - - public void setDragZoomIn(DragZoom dragZoomIn) { - this.dragZoomIn = dragZoomIn; - } - - public DragZoom getDragZoomOut() { - return dragZoomOut; - } - - public void setDragZoomOut(DragZoom dragZoomOut) { - this.dragZoomOut = dragZoomOut; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndCode.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndCode.java new file mode 100644 index 000000000..ecdb4efaa --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndCode.java @@ -0,0 +1,184 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +import lombok.Data; + +import javax.validation.constraints.NotNull; + +/** + * 解析收到的前端控制指令 + */ +@Data +public class FrontEndCode { + + + public static String encode(IFrontEndControlCode frontEndControlCode){ + return frontEndControlCode.encode(); + } + + public static IFrontEndControlCode decode(@NotNull String cmdStr) { + if (cmdStr.length() != 16) { + return null; + } + String cmdCodeStr = cmdStr.substring(6, 8); + int cmdCode = Integer.parseInt(cmdCodeStr, 16); + if (cmdCode < 39) { + // PTZ指令 + FrontEndControlCodeForPTZ codeForPTZ = new FrontEndControlCodeForPTZ(); + int zoomOut = cmdCode >> 5 & 1; + if (zoomOut == 1) { + codeForPTZ.setZoom(0); + } + int zoomIn = cmdCode >> 4 & 1; + if (zoomIn == 1) { + codeForPTZ.setZoom(1); + } + int tiltUp = cmdCode >> 3 & 1; + if (tiltUp == 1) { + codeForPTZ.setTilt(0); + } + int tiltDown = cmdCode >> 2 & 1; + if (tiltDown == 1) { + codeForPTZ.setTilt(1); + } + int panLeft = cmdCode >> 1 & 1; + if (panLeft == 1) { + codeForPTZ.setPan(0); + } + int panRight = cmdCode & 1; + if (panRight == 1) { + codeForPTZ.setPan(1); + } + String param1Str = cmdStr.substring(8, 10); + codeForPTZ.setPanSpeed(Integer.parseInt(param1Str, 16)); + String param2Str = cmdStr.substring(10, 12); + codeForPTZ.setTiltSpeed(Integer.parseInt(param2Str, 16)); + String param3Str = cmdStr.substring(12, 13); + codeForPTZ.setZoomSpeed(Integer.parseInt(param3Str, 16)); + return codeForPTZ; + }else if (cmdCode < 74) { + // FI指令 + FrontEndControlCodeForFI codeForFI = new FrontEndControlCodeForFI(); + int irisOut = cmdCode >> 3 & 1; + if (irisOut == 1) { + codeForFI.setIris(0); + } + int irisIn = cmdCode >> 2 & 1; + if (irisIn == 1) { + codeForFI.setIris(1); + } + int focusNear = cmdCode >> 1 & 1; + if (focusNear == 1) { + codeForFI.setFocus(0); + } + int focusFar = cmdCode & 1; + if (focusFar == 1) { + codeForFI.setFocus(1); + } + + String param1Str = cmdStr.substring(8, 10); + codeForFI.setFocusSpeed(Integer.parseInt(param1Str, 16)); + String param2Str = cmdStr.substring(10, 12); + codeForFI.setIrisSpeed(Integer.parseInt(param2Str, 16)); + return codeForFI; + }else if (cmdCode < 131) { + // 预置位指令 + FrontEndControlCodeForPreset codeForPreset = new FrontEndControlCodeForPreset(); + switch (cmdCode) { + case 0x81: // 设置预置位 + codeForPreset.setCode(1); + break; + case 0x82: // 调用预置位 + codeForPreset.setCode(2); + break; + case 0x83: // 删除预置位 + codeForPreset.setCode(3); + break; + default: + return null; + } + // 预置位编号 + String param2Str = cmdStr.substring(10, 12); + codeForPreset.setPresetId(Integer.parseInt(param2Str, 16)); + return codeForPreset; + }else if (cmdCode < 136) { + // 巡航指令 + FrontEndControlCodeForTour codeForTour = new FrontEndControlCodeForTour(); + String param3Str = cmdStr.substring(12, 13); + switch (cmdCode) { + case 0x84: // 加入巡航点 + codeForTour.setCode(1); + break; + case 0x85: // 删除一个巡航点 + codeForTour.setCode(2); + break; + case 0x86: // 设置巡航速度 + codeForTour.setCode(3); + codeForTour.setTourSpeed(Integer.parseInt(param3Str, 16)); + break; + case 0x87: // 设置巡航停留时间 + codeForTour.setCode(4); + codeForTour.setTourTime(Integer.parseInt(param3Str, 16)); + break; + case 0x88: // 开始巡航 + codeForTour.setCode(5); + break; + default: + return null; + } + String param1Str = cmdStr.substring(8, 10); + codeForTour.setTourId(Integer.parseInt(param1Str, 16)); + String param2Str = cmdStr.substring(10, 12); + codeForTour.setPresetId(Integer.parseInt(param2Str, 16)); + return codeForTour; + }else if (cmdCode < 138) { + // 扫描指令 + FrontEndControlCodeForScan controlCodeForScan = new FrontEndControlCodeForScan(); + String param2Str = cmdStr.substring(10, 11); + int param2Code = Integer.parseInt(param2Str, 16); + switch (cmdCode) { + case 0x89: + switch (param2Code) { + case 0x00: // 开始自动扫描 + controlCodeForScan.setCode(1); + break; + case 0x01: // 设置自动扫描左边界 + controlCodeForScan.setCode(2); + break; + case 0x02: // 设置自动扫描右边界 + controlCodeForScan.setCode(3); + break; + } + break; + case 0x8A: // 删除一个巡航点 + controlCodeForScan.setCode(4); + String param3Str = cmdStr.substring(12, 13); + controlCodeForScan.setScanSpeed(Integer.parseInt(param3Str, 16)); + break; + default: + return null; + } + String param1Str = cmdStr.substring(8, 10); + controlCodeForScan.setScanId(Integer.parseInt(param1Str, 16)); + return controlCodeForScan; + }else if (cmdCode < 141) { + // 辅助开关 + FrontEndControlCodeForAuxiliary codeForAuxiliary = new FrontEndControlCodeForAuxiliary(); + switch (cmdCode) { + case 0x8C: // 开 + codeForAuxiliary.setCode(1); + break; + case 0x8D: // 关 + codeForAuxiliary.setCode(2); + break; + default: + return null; + } + // 预置位编号 + String param2Str = cmdStr.substring(10, 12); + codeForAuxiliary.setAuxiliaryId(Integer.parseInt(param2Str, 16)); + return codeForAuxiliary; + }else { + return null; + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForAuxiliary.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForAuxiliary.java new file mode 100644 index 000000000..df81d3395 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForAuxiliary.java @@ -0,0 +1,34 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForAuxiliary implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.AUXILIARY; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 辅助开关控制指令: 1为开, 2为关, 3为设置自动扫描右边界, 4为设置自动扫描速度 + */ + @Getter + @Setter + private Integer code; + + /** + * 辅助开关编号 + */ + @Getter + @Setter + private Integer auxiliaryId; + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForFI.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForFI.java new file mode 100644 index 000000000..89c9f8d63 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForFI.java @@ -0,0 +1,48 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForFI implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.FI; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 光圈,0为缩小 1为放大 + */ + @Getter + @Setter + private Integer iris; + + /** + * 聚焦 0 近, 1远 + */ + @Getter + @Setter + private Integer focus; + + /** + * 聚焦速度 + */ + @Getter + @Setter + private Integer focusSpeed; + + /** + * 光圈速度 + */ + @Getter + @Setter + private Integer irisSpeed; + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPTZ.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPTZ.java new file mode 100644 index 000000000..37598605d --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPTZ.java @@ -0,0 +1,62 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForPTZ implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.PTZ; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 镜头变倍,0为缩小 1为放大 + */ + @Getter + @Setter + private Integer zoom; + + /** + * 云台垂直方向控制 0 为上, 1为下 + */ + @Getter + @Setter + private Integer tilt; + + /** + * 云台水平方向控制 0 为左, 1为右 + */ + @Getter + @Setter + private Integer pan; + + /** + * 水平控制速度相对值 + */ + @Getter + @Setter + private Integer panSpeed; + + /** + * 垂直控制速度相对值 + */ + @Getter + @Setter + private Integer tiltSpeed; + + /** + * 变倍控制速度相对值 + */ + @Getter + @Setter + private Integer zoomSpeed; + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPreset.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPreset.java new file mode 100644 index 000000000..f959ea552 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForPreset.java @@ -0,0 +1,35 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForPreset implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.PRESET; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 预置位指令: 1为设置预置位, 2为调用预置位, 3为删除预置位 + */ + @Getter + @Setter + private Integer code; + + /** + * 预置位编号 + */ + @Getter + @Setter + private Integer presetId; + + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForScan.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForScan.java new file mode 100644 index 000000000..3bb724437 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForScan.java @@ -0,0 +1,41 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForScan implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.SCAN; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 预置位指令: 1为开始自动扫描, 2为设置自动扫描左边界, 3为设置自动扫描右边界, 4为设置自动扫描速度 + */ + @Getter + @Setter + private Integer code; + + /** + * 自动扫描速度 + */ + @Getter + @Setter + private Integer scanSpeed; + + /** + * 扫描组号 + */ + @Getter + @Setter + private Integer scanId; + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForTour.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForTour.java new file mode 100644 index 000000000..2e27dc318 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlCodeForTour.java @@ -0,0 +1,55 @@ +package com.genersoft.iot.vmp.gb28181.bean; + + +import lombok.Getter; +import lombok.Setter; + +public class FrontEndControlCodeForTour implements IFrontEndControlCode { + + private final FrontEndControlType type = FrontEndControlType.TOUR; + + @Override + public FrontEndControlType getType() { + return type; + } + + /** + * 巡航指令: 1为加入巡航点, 2为删除一个巡航点, 3为设置巡航速度, 4为设置巡航停留时间, 5为开始巡航 + */ + @Getter + @Setter + private Integer code; + + /** + * 巡航点 + */ + @Getter + @Setter + private Integer tourId; + + /** + * 巡航停留时间 + */ + @Getter + @Setter + private Integer tourTime; + + /** + * 巡航速度 + */ + @Getter + @Setter + private Integer tourSpeed; + + /** + * 预置位编号 + */ + @Getter + @Setter + private Integer presetId; + + @Override + public String encode() { + return ""; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlType.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlType.java new file mode 100644 index 000000000..b79fbed7e --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/FrontEndControlType.java @@ -0,0 +1,6 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +public enum FrontEndControlType { + + PTZ,FI,PRESET,TOUR,SCAN,AUXILIARY +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/IFrontEndControlCode.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/IFrontEndControlCode.java new file mode 100644 index 000000000..8264e5321 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/IFrontEndControlCode.java @@ -0,0 +1,7 @@ +package com.genersoft.iot.vmp.gb28181.bean; + +public interface IFrontEndControlCode { + + FrontEndControlType getType(); + String encode(); +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteInfo.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteMessageInfo.java similarity index 93% rename from src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteInfo.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteMessageInfo.java index 57e83bd10..beadb6901 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/InviteMessageInfo.java @@ -4,7 +4,7 @@ import lombok.Data; // 从INVITE消息中解析需要的信息 @Data -public class InviteInfo { +public class InviteMessageInfo { private String requesterId; private String targetChannelId; private String sourceChannelId; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Platform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Platform.java index 74afd9ff7..13ec2c8b9 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Platform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/Platform.java @@ -127,4 +127,7 @@ public class Platform { @Schema(description = "保密属性(必选)缺省为0;0-不涉密,1-涉密") private int secrecy = 0; + + @Schema(description = "执行注册的服务ID") + private String serverId; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java index 893db116e..2a051a771 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/bean/SsrcTransaction.java @@ -27,6 +27,11 @@ public class SsrcTransaction { */ private String callId; + /** + * 关联的流应用名 + */ + private String app; + /** * 关联的流ID */ @@ -52,12 +57,13 @@ public class SsrcTransaction { */ private InviteSessionType type; - public static SsrcTransaction buildForDevice(String deviceId, Integer channelId, String callId, String stream, + public static SsrcTransaction buildForDevice(String deviceId, Integer channelId, String callId, String app, String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type) { SsrcTransaction ssrcTransaction = new SsrcTransaction(); ssrcTransaction.setDeviceId(deviceId); ssrcTransaction.setChannelId(channelId); ssrcTransaction.setCallId(callId); + ssrcTransaction.setApp(app); ssrcTransaction.setStream(stream); ssrcTransaction.setMediaServerId(mediaServerId); ssrcTransaction.setSsrc(ssrc); @@ -65,13 +71,14 @@ public class SsrcTransaction { ssrcTransaction.setType(type); return ssrcTransaction; } - public static SsrcTransaction buildForPlatform(String platformId, Integer channelId, String callId, String stream, + public static SsrcTransaction buildForPlatform(String platformId, Integer channelId, String callId, String app,String stream, String ssrc, String mediaServerId, SIPResponse response, InviteSessionType type) { SsrcTransaction ssrcTransaction = new SsrcTransaction(); ssrcTransaction.setPlatformId(platformId); ssrcTransaction.setChannelId(channelId); ssrcTransaction.setCallId(callId); ssrcTransaction.setStream(stream); + ssrcTransaction.setApp(app); ssrcTransaction.setMediaServerId(mediaServerId); ssrcTransaction.setSsrc(ssrc); ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo(response)); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java index 3db52a437..bb6d2fd34 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/CommonChannelController.java @@ -3,7 +3,10 @@ package com.genersoft.iot.vmp.gb28181.controller; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.security.JwtUtils; -import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.DeviceType; +import com.genersoft.iot.vmp.gb28181.bean.IndustryCodeType; +import com.genersoft.iot.vmp.gb28181.bean.NetworkIdentificationType; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupByGbDeviceParam; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToGroupParam; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelToRegionByGbDeviceParam; @@ -29,7 +32,6 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.http.HttpServletRequest; -import javax.sip.message.Response; import java.net.MalformedURLException; import java.net.URL; import java.util.List; @@ -139,6 +141,56 @@ public class CommonChannelController { return channelService.queryListByCivilCode(page, count, query, online, channelType, civilCode); } + + @Operation(summary = "存在行政区划但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "page", description = "当前页", required = true) + @Parameter(name = "count", description = "每页查询数量", required = true) + @Parameter(name = "query", description = "查询内容") + @Parameter(name = "online", description = "是否在线") + @Parameter(name = "channelType", description = "通道类型, 0:国标设备,1:推流设备,2:拉流代理") + @GetMapping("/civilCode/unusual/list") + public PageInfo queryListByCivilCodeForUnusual(int page, int count, + @RequestParam(required = false) String query, + @RequestParam(required = false) Boolean online, + @RequestParam(required = false) Integer channelType){ + if (ObjectUtils.isEmpty(query)){ + query = null; + } + return channelService.queryListByCivilCodeForUnusual(page, count, query, online, channelType); + } + + + @Operation(summary = "存在父节点编号但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "page", description = "当前页", required = true) + @Parameter(name = "count", description = "每页查询数量", required = true) + @Parameter(name = "query", description = "查询内容") + @Parameter(name = "online", description = "是否在线") + @Parameter(name = "channelType", description = "通道类型, 0:国标设备,1:推流设备,2:拉流代理") + @GetMapping("/parent/unusual/list") + public PageInfo queryListByParentForUnusual(int page, int count, + @RequestParam(required = false) String query, + @RequestParam(required = false) Boolean online, + @RequestParam(required = false) Integer channelType){ + if (ObjectUtils.isEmpty(query)){ + query = null; + } + return channelService.queryListByParentForUnusual(page, count, query, online, channelType); + } + + @Operation(summary = "清除存在行政区划但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "param", description = "清理参数, all为true清理所有异常数据。 否则按照传入的设备Id清理", required = true) + @PostMapping("/civilCode/unusual/clear") + public void clearChannelCivilCode(@RequestBody ChannelToRegionParam param){ + channelService.clearChannelCivilCode(param.getAll(), param.getChannelIds()); + } + + @Operation(summary = "清除存在分组节点但无法挂载的通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "param", description = "清理参数, all为true清理所有异常数据。 否则按照传入的设备Id清理", required = true) + @PostMapping("/parent/unusual/clear") + public void clearChannelParent(@RequestBody ChannelToRegionParam param){ + channelService.clearChannelParent(param.getAll(), param.getChannelIds()); + } + @Operation(summary = "获取关联业务分组通道列表", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "page", description = "当前页", required = true) @Parameter(name = "count", description = "每页查询数量", required = true) @@ -244,7 +296,7 @@ public class CommonChannelController { } catch (MalformedURLException e) { host=request.getLocalAddr(); } - streamInfo.channgeStreamIp(host); + streamInfo.changeStreamIp(host); } if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix()) && !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) { @@ -261,7 +313,7 @@ public class CommonChannelController { result.setResult(WVPResult.fail(code, msg)); } }; - channelPlayService.play(channel, null, callback); + channelPlayService.play(channel, null, userSetting.getRecordSip(), callback); return result; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java index f6e7ddcb8..f2402cf8f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceConfig.java @@ -7,30 +7,22 @@ package com.genersoft.iot.vmp.gb28181.controller; -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; +import com.genersoft.iot.vmp.gb28181.bean.BasicParam; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.ObjectUtils; +import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; -import java.util.UUID; - @Slf4j @Tag(name = "国标设备配置") @RestController @@ -40,117 +32,60 @@ public class DeviceConfig { @Autowired private IDeviceService deviceService; - @Autowired - private SIPCommander cmder; - - @Autowired - private DeferredResultHolder resultHolder; - - /** - * 看守位控制命令API接口 - * @param deviceId 设备ID - * @param channelId 通道ID - * @param name 名称 - * @param expiration 到期时间 - * @param heartBeatInterval 心跳间隔 - * @param heartBeatCount 心跳计数 - * @return - */ - @GetMapping("/basicParam/{deviceId}") + @GetMapping("/basicParam") @Operation(summary = "基本配置设置命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) - @Parameter(name = "deviceId", description = "设备国标编号", required = true) - @Parameter(name = "channelId", description = "通道国标编号", required = true) - @Parameter(name = "name", description = "名称") - @Parameter(name = "expiration", description = "到期时间") - @Parameter(name = "heartBeatInterval", description = "心跳间隔") - @Parameter(name = "heartBeatCount", description = "心跳计数") - public DeferredResult homePositionApi(@PathVariable String deviceId, - String channelId, - @RequestParam(required = false) String name, - @RequestParam(required = false) String expiration, - @RequestParam(required = false) String heartBeatInterval, - @RequestParam(required = false) String heartBeatCount) { + @Parameter(name = "basicParam", description = "基础配置参数", required = true) + public DeferredResult> homePositionApi(BasicParam basicParam) { if (log.isDebugEnabled()) { - log.debug("报警复位API调用"); + log.debug("基本配置设置命令API调用"); } - Device device = deviceService.getDeviceByDeviceId(deviceId); - String uuid = UUID.randomUUID().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + deviceId + channelId; - try { - cmder.deviceBasicConfigCmd(device, channelId, name, expiration, heartBeatInterval, heartBeatCount, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("设备配置操作失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 设备配置: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - DeferredResult result = new DeferredResult(3 * 1000L); - result.onTimeout(() -> { - log.warn(String.format("设备配置操作超时, 设备未返回应答指令")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - JSONObject json = new JSONObject(); - json.put("DeviceID", deviceId); - json.put("Status", "Timeout"); - json.put("Description", "设备配置操作超时, 设备未返回应答指令"); - msg.setData(json); //("看守位控制操作超时, 设备未返回应答指令"); - resultHolder.invokeResult(msg); + Assert.notNull(basicParam.getDeviceId(), "设备ID必须存在"); + + Device device = deviceService.getDeviceByDeviceId(basicParam.getDeviceId()); + Assert.notNull(device, "设备不存在"); + + DeferredResult> deferredResult = new DeferredResult<>(); + deviceService.deviceBasicConfig(device, basicParam, (code, msg, data) -> { + deferredResult.setResult(new WVPResult<>(code, msg, data)); }); - resultHolder.put(key, uuid, result); - return result; + + deferredResult.onTimeout(() -> { + log.warn("[设备配置] 超时, {}", device.getDeviceId()); + deferredResult.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "超时")); + }); + return deferredResult; + } - /** - * 设备配置查询请求API接口 - * @param deviceId 设备ID - * @param configType 配置类型 - * @param channelId 通道ID - * @return - */ - @Operation(summary = "设备配置查询请求", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Operation(summary = "设备配置查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) - @Parameter(name = "configType", description = "配置类型") - @GetMapping("/query/{deviceId}/{configType}") - public DeferredResult configDownloadApi(@PathVariable String deviceId, - @PathVariable String configType, - @RequestParam(required = false) String channelId) { + @Parameter(name = "configType", description = "配置类型, 可选值," + + "基本参数配置:BasicParam," + + "视频参数范围:VideoParamOpt, " + + "SVAC编码配置:SVACEncodeConfig, " + + "SVAC解码配置:SVACDecodeConfig。" + + "可同时查询多个配置类型,各类型以“/”分隔,") + @GetMapping("/query") + public DeferredResult> configDownloadApi(String deviceId,String configType, + @RequestParam(required = false) String channelId) { if (log.isDebugEnabled()) { - log.debug("设备状态查询API调用"); + log.debug("设备配置查询请求API调用"); } - String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); - String uuid = UUID.randomUUID().toString(); Device device = deviceService.getDeviceByDeviceId(deviceId); - try { - cmder.deviceConfigQuery(device, channelId, configType, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备配置失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 获取设备配置: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - DeferredResult result = new DeferredResult (3 * 1000L); - result.onTimeout(()->{ - log.warn(String.format("获取设备配置超时")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("Timeout. Device did not response to this command."); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + + DeferredResult> deferredResult = new DeferredResult<>(); + + deviceService.deviceConfigQuery(device, channelId, configType, (code, msg, data) -> { + deferredResult.setResult(new WVPResult<>(code, msg, data)); }); - resultHolder.put(key, uuid, result); - return result; + + deferredResult.onTimeout(() -> { + log.warn("[获取设备配置] 超时, {}", device.getDeviceId()); + deferredResult.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "超时")); + }); + return deferredResult; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java index 55017deb7..43a10e1e2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceControl.java @@ -7,13 +7,8 @@ package com.genersoft.iot.vmp.gb28181.controller; -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; @@ -23,16 +18,10 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.ResponseEntity; -import org.springframework.util.ObjectUtils; +import org.springframework.util.Assert; import org.springframework.web.bind.annotation.*; import org.springframework.web.context.request.async.DeferredResult; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; -import java.util.UUID; - @Tag(name = "国标设备控制") @Slf4j @RestController @@ -42,18 +31,8 @@ public class DeviceControl { @Autowired private IDeviceService deviceService; - @Autowired - private ISIPCommander cmder; - @Autowired - private DeferredResultHolder resultHolder; - - /** - * 远程启动控制命令API接口 - * - * @param deviceId 设备ID - */ - @Operation(summary = "远程启动控制命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Operation(summary = "远程启动", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @GetMapping("/teleboot/{deviceId}") public void teleBootApi(@PathVariable String deviceId) { @@ -61,194 +40,104 @@ public class DeviceControl { log.debug("设备远程启动API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - try { - cmder.teleBootCmd(device); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 远程启动: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } + Assert.notNull(device, "设备不存在"); + deviceService.teleboot(device); } - /** - * 录像控制命令API接口 - * - * @param deviceId 设备ID - * @param recordCmdStr Record:手动录像,StopRecord:停止手动录像 - * @param channelId 通道编码(可选) - */ + @Operation(summary = "录像控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @Parameter(name = "recordCmdStr", description = "命令, 可选值:Record(手动录像),StopRecord(停止手动录像)", required = true) - @GetMapping("/record/{deviceId}/{recordCmdStr}") - public DeferredResult>> recordApi(@PathVariable String deviceId, - @PathVariable String recordCmdStr, String channelId) { + @GetMapping("/record") + public DeferredResult> recordApi(String deviceId, String recordCmdStr, String channelId) { if (log.isDebugEnabled()) { log.debug("开始/停止录像API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String uuid = UUID.randomUUID().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; - DeferredResult>> result = new DeferredResult<>(3 * 1000L); - result.onTimeout(() -> { - log.warn(String.format("开始/停止录像操作超时, 设备未返回应答指令")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setId(uuid); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); - resultHolder.invokeAllResult(msg); - }); - if (resultHolder.exist(key, null)){ - return result; - } - resultHolder.put(key, uuid, result); - try { - cmder.recordCmd(device, channelId, recordCmdStr, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("开始/停止录像操作失败,错误码: %s, %s", event.statusCode, event.msg))); - resultHolder.invokeAllResult(msg); - },null); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 开始/停止录像: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } + Assert.notNull(device, "设备不存在"); + DeferredResult> deferredResult = new DeferredResult<>(); - return result; + deviceService.record(device, channelId, recordCmdStr, (code, msg, data) -> { + deferredResult.setResult(new WVPResult<>(code, msg, data)); + }); + deferredResult.onTimeout(() -> { + log.warn("[开始/停止录像] 操作超时, 设备未返回应答指令, {}", deviceId); + deferredResult.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); + }); + return deferredResult; } - /** - * 报警布防/撤防命令API接口 - * - * @param deviceId 设备ID - * @param guardCmdStr SetGuard:布防,ResetGuard:撤防 - */ - @Operation(summary = "布防/撤防命令", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Operation(summary = "布防/撤防", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "guardCmdStr", description = "命令, 可选值:SetGuard(布防),ResetGuard(撤防)", required = true) - @GetMapping("/guard/{deviceId}/{guardCmdStr}") - public DeferredResult> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) { + @GetMapping("/guard") + public DeferredResult> guardApi(String deviceId, String guardCmdStr) { if (log.isDebugEnabled()) { log.debug("布防/撤防API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + deviceId; - String uuid =UUID.randomUUID().toString(); - try { - cmder.guardCmd(device, guardCmdStr, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("布防/撤防操作失败,错误码: %s, %s", event.statusCode, event.msg))); - resultHolder.invokeResult(msg); - },null); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); - } - DeferredResult> result = new DeferredResult<>(3 * 1000L); - resultHolder.put(key, uuid, result); - result.onTimeout(() -> { - log.warn(String.format("布防/撤防操作超时, 设备未返回应答指令")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setId(uuid); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.guard(device, guardCmdStr, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[布防/撤防] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); }); - return result; } - /** - * 报警复位API接口 - * - * @param deviceId 设备ID - * @param alarmMethod 报警方式(可选) - * @param alarmType 报警类型(可选) - */ @Operation(summary = "报警复位", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) - @Parameter(name = "alarmMethod", description = "报警方式") - @Parameter(name = "alarmType", description = "报警类型") - @GetMapping("/reset_alarm/{deviceId}") - public DeferredResult>> resetAlarmApi(@PathVariable String deviceId, String channelId, + @Parameter(name = "alarmMethod", description = "报警方式, 报警方式条件(可选),取值0为全部,1为电话报警,2为设备报警,3为短信报警,4为\n" + + "GPS报警,5为视频报警,6为设备故障报警,7其他报警;可以为直接组合如12为电话报警或设备报警") + @Parameter(name = "alarmType", description = "报警类型, " + + "报警类型。" + + "报警方式为2时,不携带 AlarmType为默认的报警设备报警," + + "携带 AlarmType取值及对应报警类型如下:" + + "1-视频丢失报警;2-设备防拆报警;3-存储设备磁盘满报警;4-设备高温报警;5-设备低温报警。" + + "报警方式为5时,取值如下:" + + "1-人工视频报警;2-运动目标检测报警;3-遗留物检测报警;4-物体移除检测报警;5-绊线检测报警;" + + "6-入侵检测报警;7-逆行检测报警;8-徘徊检测报警;9-流量统计报警;10-密度检测报警;" + + "11-视频异常检测报警;12-快速移动报警。" + + "报警方式为6时,取值如下:" + + "1-存储设备磁盘故障报警;2-存储设备风扇故障报警") + @GetMapping("/reset_alarm") + public DeferredResult> resetAlarm(String deviceId, String channelId, @RequestParam(required = false) String alarmMethod, @RequestParam(required = false) String alarmType) { if (log.isDebugEnabled()) { log.debug("报警复位API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String uuid = UUID.randomUUID().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + deviceId + channelId; - try { - cmder.alarmCmd(device, alarmMethod, alarmType, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("操作失败,错误码: %s, %s", event.statusCode, event.msg))); - resultHolder.invokeResult(msg); - },null); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 报警复位: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - DeferredResult>> result = new DeferredResult<>(3 * 1000L); - result.onTimeout(() -> { - log.warn(String.format("报警复位操作超时, 设备未返回应答指令")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.resetAlarm(device, channelId, alarmMethod, alarmType, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[布防/撤防] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); }); - resultHolder.put(key, uuid, result); return result; } - /** - * 强制关键帧API接口 - * - * @param deviceId 设备ID - * @param channelId 通道ID - */ @Operation(summary = "强制关键帧", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号") - @GetMapping("/i_frame/{deviceId}") - public JSONObject iFrame(@PathVariable String deviceId, - @RequestParam(required = false) String channelId) { + @GetMapping("/i_frame") + public void iFrame(String deviceId, @RequestParam(required = false) String channelId) { if (log.isDebugEnabled()) { log.debug("强制关键帧API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - try { - cmder.iFrameCmd(device, channelId); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 强制关键帧: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - JSONObject json = new JSONObject(); - json.put("DeviceID", deviceId); - json.put("ChannelID", channelId); - json.put("Result", "OK"); - return json; + Assert.notNull(device, "设备不存在"); + deviceService.iFrame(device, channelId); } - /** - * 看守位控制命令API接口 - * - * @param deviceId 设备ID - * @param enabled 看守位使能1:开启,0:关闭 - * @param resetTime 自动归位时间间隔(可选) - * @param presetIndex 调用预置位编号(可选) - * @param channelId 通道编码(可选) - */ @Operation(summary = "看守位控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @@ -260,99 +149,54 @@ public class DeviceControl { @RequestParam(required = false) Integer resetTime, @RequestParam(required = false) Integer presetIndex) { if (log.isDebugEnabled()) { - log.debug("报警复位API调用"); + log.debug("看守位控制API调用"); } - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); - String uuid = UUID.randomUUID().toString(); Device device = deviceService.getDeviceByDeviceId(deviceId); - try { - cmder.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), String.format("操作失败,错误码: %s, %s", event.statusCode, event.msg))); - resultHolder.invokeResult(msg); - },null); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 看守位控制: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - DeferredResult> result = new DeferredResult<>(3 * 1000L); - result.onTimeout(() -> { - log.warn(String.format("看守位控制操作超时, 设备未返回应答指令")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); //("看守位控制操作超时, 设备未返回应答指令"); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.homePosition(device, channelId, enabled, resetTime, presetIndex, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[看守位控制] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); }); - resultHolder.put(key, uuid, result); return result; } - /** - * 拉框放大 - * @param deviceId 设备id - * @param channelId 通道id - * @param length 播放窗口长度像素值 - * @param width 播放窗口宽度像素值 - * @param midpointx 拉框中心的横轴坐标像素值 - * @param midpointy 拉框中心的纵轴坐标像素值 - * @param lengthx 拉框长度像素值 - * @param lengthy 拉框宽度像素值 - * @return - */ @Operation(summary = "拉框放大", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @Parameter(name = "length", description = "播放窗口长度像素值", required = true) + @Parameter(name = "width", description = "播放窗口宽度像素值", required = true) @Parameter(name = "midpointx", description = "拉框中心的横轴坐标像素值", required = true) @Parameter(name = "midpointy", description = "拉框中心的纵轴坐标像素值", required = true) @Parameter(name = "lengthx", description = "拉框长度像素值", required = true) - @Parameter(name = "lengthy", description = "lengthy", required = true) + @Parameter(name = "lengthy", description = "拉框宽度像素值", required = true) @GetMapping("drag_zoom/zoom_in") - public void dragZoomIn(@RequestParam String deviceId, - @RequestParam(required = false) String channelId, + public DeferredResult> dragZoomIn(@RequestParam String deviceId, String channelId, @RequestParam int length, @RequestParam int width, @RequestParam int midpointx, @RequestParam int midpointy, @RequestParam int lengthx, - @RequestParam int lengthy) throws RuntimeException { + @RequestParam int lengthy) { if (log.isDebugEnabled()) { log.debug(String.format("设备拉框放大 API调用,deviceId:%s ,channelId:%s ,length:%d ,width:%d ,midpointx:%d ,midpointy:%d ,lengthx:%d ,lengthy:%d",deviceId, channelId, length, width, midpointx, midpointy,lengthx, lengthy)); } Device device = deviceService.getDeviceByDeviceId(deviceId); - StringBuffer cmdXml = new StringBuffer(200); - cmdXml.append("\r\n"); - cmdXml.append("" + length+ "\r\n"); - cmdXml.append("" + width+ "\r\n"); - cmdXml.append("" + midpointx+ "\r\n"); - cmdXml.append("" + midpointy+ "\r\n"); - cmdXml.append("" + lengthx+ "\r\n"); - cmdXml.append("" + lengthy+ "\r\n"); - cmdXml.append("\r\n"); - try { - cmder.dragZoomCmd(device, channelId, cmdXml.toString()); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 拉框放大: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.dragZoomIn(device, channelId, length, width, midpointx, midpointy, lengthx,lengthy, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[设备拉框放大] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); + }); + return result; } - /** - * 拉框缩小 - * @param deviceId 设备id - * @param channelId 通道id - * @param length 播放窗口长度像素值 - * @param width 播放窗口宽度像素值 - * @param midpointx 拉框中心的横轴坐标像素值 - * @param midpointy 拉框中心的纵轴坐标像素值 - * @param lengthx 拉框长度像素值 - * @param lengthy 拉框宽度像素值 - * @return - */ @Operation(summary = "拉框缩小", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号") @@ -363,7 +207,7 @@ public class DeviceControl { @Parameter(name = "lengthx", description = "拉框长度像素值", required = true) @Parameter(name = "lengthy", description = "拉框宽度像素值", required = true) @GetMapping("/drag_zoom/zoom_out") - public void dragZoomOut(@RequestParam String deviceId, + public DeferredResult> dragZoomOut(@RequestParam String deviceId, @RequestParam(required = false) String channelId, @RequestParam int length, @RequestParam int width, @@ -376,20 +220,15 @@ public class DeviceControl { log.debug(String.format("设备拉框缩小 API调用,deviceId:%s ,channelId:%s ,length:%d ,width:%d ,midpointx:%d ,midpointy:%d ,lengthx:%d ,lengthy:%d",deviceId, channelId, length, width, midpointx, midpointy,lengthx, lengthy)); } Device device = deviceService.getDeviceByDeviceId(deviceId); - StringBuffer cmdXml = new StringBuffer(200); - cmdXml.append("\r\n"); - cmdXml.append("" + length+ "\r\n"); - cmdXml.append("" + width+ "\r\n"); - cmdXml.append("" + midpointx+ "\r\n"); - cmdXml.append("" + midpointy+ "\r\n"); - cmdXml.append("" + lengthx+ "\r\n"); - cmdXml.append("" + lengthy+ "\r\n"); - cmdXml.append("\r\n"); - try { - cmder.dragZoomCmd(device, channelId, cmdXml.toString()); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 拉框缩小: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.dragZoomOut(device, channelId, length, width, midpointx, midpointy, lengthx,lengthy, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[设备拉框放大] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); + }); + return result; } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java index 5e9ee17e7..c18df8f59 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/DeviceQuery.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.gb28181.controller; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.conf.DynamicTask; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.Device; @@ -14,8 +15,8 @@ import com.genersoft.iot.vmp.gb28181.task.ISubscribeTask; import com.genersoft.iot.vmp.gb28181.task.impl.CatalogSubscribeTask; import com.genersoft.iot.vmp.gb28181.task.impl.MobilePositionSubscribeTask; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.github.pagehelper.PageInfo; @@ -27,9 +28,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.utils.IOUtils; import org.apache.ibatis.annotations.Options; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; @@ -37,17 +36,13 @@ import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; -import java.text.ParseException; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.UUID; @Tag(name = "国标设备查询", description = "国标设备查询") @SuppressWarnings("rawtypes") @@ -61,24 +56,25 @@ public class DeviceQuery { @Autowired private IInviteStreamService inviteStreamService; - - @Autowired - private SIPCommander cmder; - - @Autowired - private DeferredResultHolder resultHolder; @Autowired private IDeviceService deviceService; + @Autowired + private ISIPCommander cmder; + + @Autowired + private DeferredResultHolder resultHolder; + + @Autowired + private UserSetting userSetting; + @Autowired private DynamicTask dynamicTask; - /** - * 使用ID查询国标设备 - * @param deviceId 国标ID - * @return 国标设备 - */ + @Autowired + private IRedisRpcService redisRpcService; + @Operation(summary = "查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @GetMapping("/devices/{deviceId}") @@ -87,12 +83,7 @@ public class DeviceQuery { return deviceService.getDeviceByDeviceId(deviceId); } - /** - * 分页查询国标设备 - * @param page 当前页 - * @param count 每页查询数量 - * @return 分页国标列表 - */ + @Operation(summary = "分页查询国标设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "page", description = "当前页", required = true) @Parameter(name = "count", description = "每页查询数量", required = true) @@ -107,9 +98,7 @@ public class DeviceQuery { return deviceService.getAll(page, count, query, status); } - /** - * 分页查询通道数 - */ + @GetMapping("/devices/{deviceId}/channels") @Operation(summary = "分页查询通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @@ -130,9 +119,7 @@ public class DeviceQuery { return deviceChannelService.queryChannelsByDeviceId(deviceId, query, channelType, online, page, count); } - /** - * 同步设备通道 - */ + @Operation(summary = "同步设备通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @GetMapping("/devices/{deviceId}/sync") @@ -142,37 +129,11 @@ public class DeviceQuery { log.debug("设备通道信息同步API调用,deviceId:" + deviceId); } Device device = deviceService.getDeviceByDeviceId(deviceId); - boolean status = deviceService.isSyncRunning(deviceId); - // 已存在则返回进度 - if (deviceService.isSyncRunning(deviceId)) { - SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId); - WVPResult wvpResult = new WVPResult(); - if (channelSyncStatus.getErrorMsg() != null) { - wvpResult.setCode(ErrorCode.ERROR100.getCode()); - wvpResult.setMsg(channelSyncStatus.getErrorMsg()); - }else if (channelSyncStatus.getTotal() == null || channelSyncStatus.getTotal() == 0){ - wvpResult.setCode(ErrorCode.SUCCESS.getCode()); - wvpResult.setMsg("等待通道信息..."); - }else { - wvpResult.setCode(ErrorCode.SUCCESS.getCode()); - wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); - wvpResult.setData(channelSyncStatus); - } - return wvpResult; - } - deviceService.sync(device); - WVPResult wvpResult = new WVPResult<>(); - wvpResult.setCode(0); - wvpResult.setMsg("开始同步"); - return wvpResult; + return deviceService.devicesSync(device); + } - /** - * 移除设备 - * @param deviceId 设备id - * @return - */ @Operation(summary = "移除设备", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @DeleteMapping("/devices/{deviceId}/delete") @@ -207,17 +168,6 @@ public class DeviceQuery { } } - /** - * 分页查询子目录通道 - * @param deviceId 通道id - * @param channelId 通道id - * @param page 当前页 - * @param count 每页条数 - * @param query 查询内容 - * @param online 是否在线 - * @param channelType 通道类型 - * @return 子通道列表 - */ @Operation(summary = "分页查询子目录通道", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @@ -241,7 +191,7 @@ public class DeviceQuery { return deviceChannelPageResult; } - return deviceChannelService.getSubChannels(deviceChannel.getDeviceDbId(), channelId, query, channelType, online, page, count); + return deviceChannelService.getSubChannels(deviceChannel.getDataDeviceId(), channelId, query, channelType, online, page, count); } @Operation(summary = "开启/关闭通道的音频", security = @SecurityRequirement(name = JwtUtils.HEADER)) @@ -259,13 +209,15 @@ public class DeviceQuery { public void updateChannelStreamIdentification(DeviceChannel channel){ deviceChannelService.updateChannelStreamIdentification(channel); } + @Operation(summary = "获取单个通道详情", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "deviceId", description = "设备的国标编码", required = true) + @Parameter(name = "channelDeviceId", description = "通道的国标编码", required = true) + @GetMapping("/channel/one") + public DeviceChannel getChannel(String deviceId, String channelDeviceId){ + return deviceChannelService.getOne(deviceId, channelDeviceId); + } + - /** - * 修改数据流传输模式 - * @param deviceId 设备id - * @param streamMode 数据流传输模式 - * @return - */ @Operation(summary = "修改数据流传输模式", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "streamMode", description = "数据流传输模式, 取值:" + @@ -277,11 +229,7 @@ public class DeviceQuery { deviceService.updateCustomDevice(device); } - /** - * 添加设备信息 - * @param device 设备信息 - * @return - */ + @Operation(summary = "添加设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "device", description = "设备", required = true) @PostMapping("/device/add/") @@ -299,11 +247,7 @@ public class DeviceQuery { deviceService.addDevice(device); } - /** - * 更新设备信息 - * @param device 设备信息 - * @return - */ + @Operation(summary = "更新设备信息", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "device", description = "设备", required = true) @PostMapping("/device/update/") @@ -314,72 +258,37 @@ public class DeviceQuery { deviceService.updateCustomDevice(device); } - /** - * 设备状态查询请求API接口 - * - * @param deviceId 设备id - */ @Operation(summary = "设备状态查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) @GetMapping("/devices/{deviceId}/status") - public DeferredResult> deviceStatusApi(@PathVariable String deviceId) { + public DeferredResult> deviceStatusApi(@PathVariable String deviceId) { if (log.isDebugEnabled()) { log.debug("设备状态查询API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String uuid = UUID.randomUUID().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId; - DeferredResult> result = new DeferredResult>(2*1000L); - if(device == null) { - result.setResult(new ResponseEntity(String.format("设备%s不存在", deviceId),HttpStatus.OK)); - return result; - } - try { - cmder.deviceStatusQuery(device, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备状态失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 获取设备状态: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - result.onTimeout(()->{ - log.warn(String.format("获取设备状态超时")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("Timeout. Device did not response to this command."); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.deviceStatus(device, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[设备状态查询] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); }); - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + deviceId, uuid, result); return result; } - /** - * 设备报警查询请求API接口 - * @param deviceId 设备id - * @param startPriority 报警起始级别(可选) - * @param endPriority 报警终止级别(可选) - * @param alarmMethod 报警方式条件(可选) - * @param alarmType 报警类型 - * @param startTime 报警发生起始时间(可选) - * @param endTime 报警发生终止时间(可选) - * @return true = 命令发送成功 - */ @Operation(summary = "设备报警查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "deviceId", description = "设备国标编号", required = true) - @Parameter(name = "startPriority", description = "报警起始级别") - @Parameter(name = "endPriority", description = "报警终止级别") - @Parameter(name = "alarmMethod", description = "报警方式条件") + @Parameter(name = "startPriority", description = "报警起始级别, 0为全部,1为一级警情,2为二级警情,3为三级警情,4为四级警情") + @Parameter(name = "endPriority", description = "报警终止级别, ,0为全部,1为一级警情,2为二级警情,3为三级警情,4为四级警情") + @Parameter(name = "alarmMethod", description = "报警方式条件,取值0为全部,1为电话报警,2为设备报警,3为短信报警,4为GPS报警," + + "5为视频报警,6为设备故障报警,7其他报警;可以为直接组合如12为电话报警或设备报警") @Parameter(name = "alarmType", description = "报警类型") @Parameter(name = "startTime", description = "报警发生起始时间") @Parameter(name = "endTime", description = "报警发生终止时间") - @GetMapping("/alarm/{deviceId}") - public DeferredResult> alarmApi(@PathVariable String deviceId, + @GetMapping("/alarm") + public DeferredResult> alarmApi(String deviceId, @RequestParam(required = false) String startPriority, @RequestParam(required = false) String endPriority, @RequestParam(required = false) String alarmMethod, @@ -390,31 +299,35 @@ public class DeviceQuery { log.debug("设备报警查询API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String key = DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId; - String uuid = UUID.randomUUID().toString(); - try { - cmder.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("设备报警查询失败,错误码: %s, %s",event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 设备报警查询: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - DeferredResult> result = new DeferredResult> (3 * 1000L); - result.onTimeout(()->{ - log.warn(String.format("设备报警查询超时")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("设备报警查询超时"); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.alarm(device, startPriority,endPriority ,alarmMethod ,alarmType ,startTime ,endTime, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[设备报警查询] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); + }); + return result; + } + + @Operation(summary = "设备信息查询", security = @SecurityRequirement(name = JwtUtils.HEADER)) + @Parameter(name = "deviceId", description = "设备国标编号", required = true) + @GetMapping("/info") + public DeferredResult> deviceInfo(String deviceId) { + if (log.isDebugEnabled()) { + log.debug("设备信息查询API调用"); + } + Device device = deviceService.getDeviceByDeviceId(deviceId); + Assert.notNull(device, "设备不存在"); + DeferredResult> result = new DeferredResult<>(); + deviceService.deviceInfo(device, (code, msg, data) -> { + result.setResult(new WVPResult<>(code, msg, data)); + }); + result.onTimeout(() -> { + log.warn("[设备信息查询] 操作超时, 设备未返回应答指令, {}", deviceId); + result.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "操作超时, 设备未应答")); }); - resultHolder.put(DeferredResultHolder.CALLBACK_CMD_ALARM + deviceId, uuid, result); return result; } @@ -489,4 +402,21 @@ public class DeviceQuery { public DeviceChannel getRawChannel(int id) { return deviceChannelService.getRawChannel(id); } + + @GetMapping("/subscribe/catalog") + @Operation(summary = "开启/关闭目录订阅") + @Parameter(name = "id", description = "通道的Id", required = true) + @Parameter(name = "cycle", description = "订阅周期", required = true) + public void subscribeCatalog(int id, int cycle) { + deviceService.subscribeCatalog(id, cycle); + } + + @GetMapping("/subscribe/mobile-position") + @Operation(summary = "开启/关闭移动位置订阅") + @Parameter(name = "id", description = "通道的Id", required = true) + @Parameter(name = "cycle", description = "订阅周期", required = true) + @Parameter(name = "interval", description = "报送间隔", required = true) + public void subscribeMobilePosition(int id, int cycle, int interval) { + deviceService.subscribeMobilePosition(id, cycle, interval); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java index e48ae616e..4b9129af1 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/GBRecordController.java @@ -1,9 +1,9 @@ package com.genersoft.iot.vmp.gb28181.controller; +import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; -import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; @@ -32,10 +32,8 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; import javax.servlet.http.HttpServletRequest; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; import java.util.UUID; +import java.util.concurrent.TimeUnit; @Tag(name = "国标录像") @Slf4j @@ -72,7 +70,7 @@ public class GBRecordController { if (log.isDebugEnabled()) { log.debug(String.format("录像信息查询 API调用,deviceId:%s ,startTime:%s, endTime:%s",deviceId, startTime, endTime)); } - DeferredResult> result = new DeferredResult<>(); + DeferredResult> result = new DeferredResult<>(Long.valueOf(userSetting.getRecordInfoTimeout()), TimeUnit.MILLISECONDS); if (!DateUtil.verification(startTime, DateUtil.formatter)){ throw new ControllerException(ErrorCode.ERROR100.getCode(), "startTime格式为" + DateUtil.PATTERN); } @@ -81,35 +79,25 @@ public class GBRecordController { } Device device = deviceService.getDeviceByDeviceId(deviceId); - // 指定超时时间 1分钟30秒 - String uuid = UUID.randomUUID().toString(); - int sn = (int)((Math.random()*9+1)*100000); - String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - try { - cmder.recordInfoQuery(device, channelId, startTime, endTime, sn, null, null, null, (eventResult -> { - WVPResult wvpResult = new WVPResult<>(); - wvpResult.setCode(ErrorCode.ERROR100.getCode()); - wvpResult.setMsg("查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg); - msg.setData(wvpResult); - resultHolder.invokeResult(msg); - })); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 查询录像: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), deviceId + " 不存在"); } - - // 录像查询以channelId作为deviceId查询 - resultHolder.put(key, uuid, result); + DeviceChannel channel = channelService.getOneForSource(device.getId(), channelId); + if (channel == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), channelId + " 不存在"); + } + channelService.queryRecordInfo(device, channel, startTime, endTime, (code, msg, data)->{ + WVPResult wvpResult = new WVPResult<>(); + wvpResult.setCode(code); + wvpResult.setMsg(msg); + wvpResult.setData(data); + result.setResult(wvpResult); + }); result.onTimeout(()->{ - msg.setData("timeout"); WVPResult wvpResult = new WVPResult<>(); wvpResult.setCode(ErrorCode.ERROR100.getCode()); wvpResult.setMsg("timeout"); - msg.setData(wvpResult); - resultHolder.invokeResult(msg); + result.setResult(wvpResult); }); return result; } @@ -159,7 +147,7 @@ public class GBRecordController { if (data != null) { StreamInfo streamInfo = (StreamInfo)data; if (userSetting.getUseSourceIpAsStreamIp()) { - streamInfo.channgeStreamIp(request.getLocalAddr()); + streamInfo.changeStreamIp(request.getLocalAddr()); } wvpResult.setData(new StreamContent(streamInfo)); } @@ -179,7 +167,7 @@ public class GBRecordController { @Parameter(name = "channelId", description = "通道国标编号", required = true) @Parameter(name = "stream", description = "流ID", required = true) @GetMapping("/download/stop/{deviceId}/{channelId}/{stream}") - public void playStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { + public void downloadStop(@PathVariable String deviceId, @PathVariable String channelId, @PathVariable String stream) { if (log.isDebugEnabled()) { log.debug(String.format("设备历史媒体下载停止 API调用,deviceId/channelId:%s_%s", deviceId, channelId)); @@ -191,14 +179,13 @@ public class GBRecordController { Device device = deviceService.getDeviceByDeviceId(deviceId); if (device == null) { - throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + "未找到"); + throw new ControllerException(ErrorCode.ERROR400.getCode(), "设备:" + deviceId + " 未找到"); } - - try { - cmder.streamByeCmd(device, channelId, stream, null); - } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { - log.warn("[停止历史媒体下载]停止历史媒体下载,发送BYE失败 {}", e.getMessage()); + DeviceChannel deviceChannel = channelService.getOneForSource(deviceId, channelId); + if (deviceChannel == null) { + throw new ControllerException(ErrorCode.ERROR400.getCode(), "通道:" + channelId + " 未找到"); } + playService.stop(InviteSessionType.DOWNLOAD, device, deviceChannel, stream); } @Operation(summary = "获取历史媒体下载进度", security = @SecurityRequirement(name = JwtUtils.HEADER)) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlayController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlayController.java index e7a8b1c87..4eb682156 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlayController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlayController.java @@ -19,6 +19,7 @@ import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.service.IMediaServerService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; @@ -91,31 +92,22 @@ public class PlayController { Assert.notNull(deviceId, "设备不存在"); DeviceChannel channel = deviceChannelService.getOne(deviceId, channelId); Assert.notNull(channel, "通道不存在"); - MediaServer newMediaServerItem = playService.getNewMediaServerItem(device); - RequestMessage requestMessage = new RequestMessage(); - String key = DeferredResultHolder.CALLBACK_CMD_PLAY + deviceId + channelId; - requestMessage.setKey(key); - String uuid = UUID.randomUUID().toString(); - requestMessage.setId(uuid); DeferredResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); result.onTimeout(()->{ log.info("[点播等待超时] deviceId:{}, channelId:{}, ", deviceId, channelId); // 释放rtpserver - WVPResult wvpResult = new WVPResult<>(); + WVPResult wvpResult = new WVPResult<>(); wvpResult.setCode(ErrorCode.ERROR100.getCode()); wvpResult.setMsg("点播超时"); - requestMessage.setData(wvpResult); - resultHolder.invokeAllResult(requestMessage); + result.setResult(wvpResult); + inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); deviceChannelService.stopPlay(channel.getId()); }); - // 录像查询以channelId作为deviceId查询 - resultHolder.put(key, uuid, result); - - playService.play(newMediaServerItem, deviceId, channelId, null, (code, msg, streamInfo) -> { + ErrorCallback callback = (code, msg, streamInfo) -> { WVPResult wvpResult = new WVPResult<>(); if (code == InviteErrorCode.SUCCESS.getCode()) { wvpResult.setCode(ErrorCode.SUCCESS.getCode()); @@ -131,10 +123,10 @@ public class PlayController { } catch (MalformedURLException e) { host=request.getLocalAddr(); } - streamInfo.channgeStreamIp(host); + streamInfo.changeStreamIp(host); } - if (!ObjectUtils.isEmpty(newMediaServerItem.getTranscodeSuffix()) && !"null".equalsIgnoreCase(newMediaServerItem.getTranscodeSuffix())) { - streamInfo.setStream(streamInfo.getStream() + "_" + newMediaServerItem.getTranscodeSuffix()); + if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix()) && !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) { + streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix()); } wvpResult.setData(new StreamContent(streamInfo)); }else { @@ -145,10 +137,9 @@ public class PlayController { wvpResult.setCode(code); wvpResult.setMsg(msg); } - requestMessage.setData(wvpResult); - // 此处必须释放所有请求 - resultHolder.invokeAllResult(requestMessage); - }); + result.setResult(wvpResult); + }; + playService.play(device, channel, callback); return result; } @@ -207,16 +198,8 @@ public class PlayController { if (log.isDebugEnabled()) { log.debug("语音广播API调用"); } - Device device = deviceService.getDeviceByDeviceId(deviceId); - if (device == null) { - throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId); - } - DeviceChannel channel = deviceChannelService.getOne(deviceId, channelId); - if (channel == null) { - throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelId); - } - return playService.audioBroadcast(device, channel, broadcastMode); + return playService.audioBroadcast(deviceId, channelId, broadcastMode); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java index 210b022f7..11b221592 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PlaybackController.java @@ -122,7 +122,7 @@ public class PlaybackController { } catch (MalformedURLException e) { host=request.getLocalAddr(); } - streamInfo.channgeStreamIp(host); + streamInfo.changeStreamIp(host); } wvpResult.setData(new StreamContent(streamInfo)); } @@ -156,7 +156,7 @@ public class PlaybackController { } DeviceChannel deviceChannel = channelService.getOneForSource(deviceId, channelId); if (deviceChannel == null) { - throw new ControllerException(ErrorCode.ERROR400.getCode(), "通道:" + deviceChannel + " 未找到"); + throw new ControllerException(ErrorCode.ERROR400.getCode(), "通道:" + channelId + " 未找到"); } playService.stop(InviteSessionType.PLAYBACK, device, deviceChannel, stream); } @@ -166,8 +166,7 @@ public class PlaybackController { @Parameter(name = "streamId", description = "回放流ID", required = true) @GetMapping("/pause/{streamId}") public void playPause(@PathVariable String streamId) { - log.info("playPause: "+streamId); - + log.info("[回放暂停] streamId: {}", streamId); try { playService.pauseRtp(streamId); } catch (ServiceException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PtzController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PtzController.java index 8749ef48b..2f3b3a950 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PtzController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/PtzController.java @@ -5,25 +5,24 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IPTZService; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.util.ObjectUtils; -import org.springframework.web.bind.annotation.*; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import org.springframework.web.context.request.async.DeferredResult; -import javax.sip.InvalidArgumentException; -import javax.sip.SipException; -import java.text.ParseException; -import java.util.UUID; - @Tag(name = "前端设备控制") @Slf4j @RestController @@ -36,6 +35,9 @@ public class PtzController { @Autowired private IDeviceService deviceService; + @Autowired + private IPTZService ptzService; + @Autowired private DeferredResultHolder resultHolder; @@ -45,30 +47,29 @@ public class PtzController { @Parameter(name = "cmdCode", description = "指令码(对应国标文档指令格式中的字节4)", required = true) @Parameter(name = "parameter1", description = "数据一(对应国标文档指令格式中的字节5, 范围0-255)", required = true) @Parameter(name = "parameter2", description = "数据二(对应国标文档指令格式中的字节6, 范围0-255)", required = true) - @Parameter(name = "combindCode2", description = "组合码二(对应国标文档指令格式中的字节7, 范围0-16)", required = true) + @Parameter(name = "combindCode2", description = "组合码二(对应国标文档指令格式中的字节7, 范围0-15)", required = true) @GetMapping("/common/{deviceId}/{channelId}") public void frontEndCommand(@PathVariable String deviceId,@PathVariable String channelId,Integer cmdCode, Integer parameter1, Integer parameter2, Integer combindCode2){ if (log.isDebugEnabled()) { log.debug(String.format("设备云台控制 API调用,deviceId:%s ,channelId:%s ,cmdCode:%d parameter1:%d parameter2:%d",deviceId, channelId, cmdCode, parameter1, parameter2)); } - Device device = deviceService.getDeviceByDeviceId(deviceId); if (parameter1 == null || parameter1 < 0 || parameter1 > 255) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "parameter1 为 1-255的数字"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "parameter1 为 0-255的数字"); } if (parameter2 == null || parameter2 < 0 || parameter2 > 255) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "parameter1 为 1-255的数字"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "parameter2 为 0-255的数字"); } - if (combindCode2 == null || combindCode2 < 0 || combindCode2 > 16) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "parameter1 为 1-255的数字"); - } - try { - cmder.frontEndCmd(device, channelId, cmdCode, parameter1, parameter2, combindCode2); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 前端控制: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + if (combindCode2 == null || combindCode2 < 0 || combindCode2 > 15) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "combindCode2 为 0-15的数字"); } + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + Assert.notNull(device, "设备[" + deviceId + "]不存在"); + + ptzService.frontEndCommand(device, channelId, cmdCode, parameter1, parameter2, combindCode2); } @Operation(summary = "云台控制", security = @SecurityRequirement(name = JwtUtils.HEADER)) @@ -77,7 +78,7 @@ public class PtzController { @Parameter(name = "command", description = "控制指令,允许值: left, right, up, down, upleft, upright, downleft, downright, zoomin, zoomout, stop", required = true) @Parameter(name = "horizonSpeed", description = "水平速度(0-255)", required = true) @Parameter(name = "verticalSpeed", description = "垂直速度(0-255)", required = true) - @Parameter(name = "zoomSpeed", description = "缩放速度(0-16)", required = true) + @Parameter(name = "zoomSpeed", description = "缩放速度(0-15)", required = true) @GetMapping("/ptz/{deviceId}/{channelId}") public void ptz(@PathVariable String deviceId,@PathVariable String channelId, String command, Integer horizonSpeed, Integer verticalSpeed, Integer zoomSpeed){ @@ -87,17 +88,17 @@ public class PtzController { if (horizonSpeed == null) { horizonSpeed = 100; }else if (horizonSpeed < 0 || horizonSpeed > 255) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "horizonSpeed 为 1-255的数字"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "horizonSpeed 为 0-255的数字"); } if (verticalSpeed == null) { verticalSpeed = 100; }else if (verticalSpeed < 0 || verticalSpeed > 255) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "verticalSpeed 为 1-255的数字"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "verticalSpeed 为 0-255的数字"); } if (zoomSpeed == null) { zoomSpeed = 16; - }else if (zoomSpeed < 0 || zoomSpeed > 16) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "zoomSpeed 为 1-255的数字"); + }else if (zoomSpeed < 0 || zoomSpeed > 15) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "zoomSpeed 为 0-15的数字"); } int cmdCode = 0; @@ -156,6 +157,12 @@ public class PtzController { log.debug("设备光圈控制 API调用,deviceId:{} ,channelId:{} ,command:{} ,speed:{} ",deviceId, channelId, command, speed); } + if (speed == null) { + speed = 100; + }else if (speed < 0 || speed > 255) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-255的数字"); + } + int cmdCode = 0x40; switch (command){ case "in": @@ -188,7 +195,7 @@ public class PtzController { if (speed == null) { speed = 100; }else if (speed < 0 || speed > 255) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "verticalSpeed 为 1-255的数字"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "speed 为 0-255的数字"); } int cmdCode = 0x40; @@ -212,40 +219,22 @@ public class PtzController { @Parameter(name = "deviceId", description = "设备国标编号", required = true) @Parameter(name = "channelId", description = "通道国标编号", required = true) @GetMapping("/preset/query/{deviceId}/{channelId}") - public DeferredResult queryPreset(@PathVariable String deviceId, @PathVariable String channelId) { + public DeferredResult> queryPreset(@PathVariable String deviceId, @PathVariable String channelId) { if (log.isDebugEnabled()) { log.debug("设备预置位查询API调用"); } Device device = deviceService.getDeviceByDeviceId(deviceId); - String uuid = UUID.randomUUID().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + (ObjectUtils.isEmpty(channelId) ? deviceId : channelId); - DeferredResult result = new DeferredResult (3 * 1000L); - result.onTimeout(()->{ - log.warn(String.format("获取设备预置位超时")); - // 释放rtpserver - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData("获取设备预置位超时"); - resultHolder.invokeResult(msg); + Assert.notNull(device, "设备不存在"); + DeferredResult> deferredResult = new DeferredResult<> (3 * 1000L); + deviceService.queryPreset(device, channelId, (code, msg, data) -> { + deferredResult.setResult(new WVPResult<>(code, msg, data)); }); - if (resultHolder.exist(key, null)) { - return result; - } - resultHolder.put(key, uuid, result); - try { - cmder.presetQuery(device, channelId, event -> { - RequestMessage msg = new RequestMessage(); - msg.setId(uuid); - msg.setKey(key); - msg.setData(String.format("获取设备预置位失败,错误码: %s, %s", event.statusCode, event.msg)); - resultHolder.invokeResult(msg); - }); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 获取设备预置位: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); - } - return result; + + deferredResult.onTimeout(()->{ + log.warn("[获取设备预置位] 超时, {}", device.getDeviceId()); + deferredResult.setResult(WVPResult.fail(ErrorCode.ERROR100.getCode(), "超时")); + }); + return deferredResult; } @Operation(summary = "预置位指令-设置预置位", security = @SecurityRequirement(name = JwtUtils.HEADER)) diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java index 3fd7f79a3..d49c28626 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/RegionController.java @@ -124,4 +124,20 @@ public class RegionController { public void sync(){ regionService.syncFromChannel(); } + + @Operation(summary = "根据行政区划编号从文件中查询层级和描述") + @ResponseBody + @GetMapping("/description") + public String getDescription(String civilCode){ + return regionService.getDescription(civilCode); + } + + @Operation(summary = "根据行政区划编号从文件中查询层级并添加") + @ResponseBody + @GetMapping("/addByCivilCode") + public void addByCivilCode(String civilCode){ + regionService.addByCivilCode(civilCode); + } + + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelToRegionParam.java b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelToRegionParam.java index 32505b235..7f740041d 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelToRegionParam.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/controller/bean/ChannelToRegionParam.java @@ -1,13 +1,21 @@ package com.genersoft.iot.vmp.gb28181.controller.bean; +import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import java.util.List; @Data +@Schema(description="提交行政区划关联多个通道的参数") public class ChannelToRegionParam { + @Schema(description = "行政区划编号") private String civilCode; + + @Schema(description = "选择的通道, 和all参数二选一") private List channelIds; + @Schema(description = "所有通道, 和channelIds参数二选一") + private Boolean all; + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java index 37ec6adee..3b71eb1da 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java @@ -20,9 +20,8 @@ public interface CommonGBChannelMapper { @Insert(" "}) - int updateStatusById(@Param("gbId") int gbId, @Param("status") int status); + int updateStatusById(@Param("gbId") int gbId, @Param("status") String status); @Update(""}) - void reset(@Param("id") int id, @Param("gbDeviceDbId") int gbDeviceDbId, @Param("updateTime") String updateTime); + void reset(@Param("id") int id, @Param("dataType") Integer dataType, @Param("dataDeviceId") int dataDeviceId, @Param("updateTime") String updateTime); @SelectProvider(type = ChannelProvider.class, method = "queryByIds") @@ -253,21 +250,15 @@ public interface CommonGBChannelMapper { ""}) void batchDelete(List channelListInDb); - @SelectProvider(type = ChannelProvider.class, method = "queryByStreamPushId") - CommonGBChannel queryByStreamPushId(@Param("streamPushId") Integer streamPushId); - - @SelectProvider(type = ChannelProvider.class, method = "queryByStreamProxyId") - CommonGBChannel queryByStreamProxyId(@Param("streamProxyId") Integer streamProxyId); - @SelectProvider(type = ChannelProvider.class, method = "queryListByCivilCode") List queryListByCivilCode(@Param("query") String query, @Param("online") Boolean online, - @Param("channelType") Integer channelType, @Param("civilCode") String civilCode); + @Param("dataType") Integer dataType, @Param("civilCode") String civilCode); @SelectProvider(type = ChannelProvider.class, method = "queryListByParentId") List queryListByParentId(@Param("query") String query, @Param("online") Boolean online, - @Param("channelType") Integer channelType, @Param("groupDeviceId") String groupDeviceId); + @Param("dataType") Integer dataType, @Param("groupDeviceId") String groupDeviceId); @@ -316,18 +307,26 @@ public interface CommonGBChannelMapper { " "}) int removeCivilCodeByChannels(List channelList); + @Update(value = {" "}) + int removeCivilCodeByChannelIds(List channelIdList); + @SelectProvider(type = ChannelProvider.class, method = "queryByCivilCode") List queryByCivilCode(@Param("civilCode") String civilCode); @SelectProvider(type = ChannelProvider.class, method = "queryByGbDeviceIds") - List queryByGbDeviceIds(List deviceIds); + List queryByGbDeviceIds(@Param("dataType") Integer dataType, List deviceIds); @Select(value = {" "}) - List queryByGbDeviceIdsForIds(List deviceIds); + List queryByGbDeviceIdsForIds(@Param("dataType") Integer dataType, List deviceIds); @SelectProvider(type = ChannelProvider.class, method = "queryByGroupList") List queryByGroupList(List groupList); @@ -449,19 +448,20 @@ public interface CommonGBChannelMapper { int updateCivilCodeByChannelList(@Param("civilCode") String civilCode, List channelList); @SelectProvider(type = ChannelProvider.class, method = "queryListByStreamPushList") - List queryListByStreamPushList(List streamPushList); + List queryListByStreamPushList(@Param("dataType") Integer dataType, List streamPushList); @Update(value = {" "}) - void updateGpsByDeviceIdForStreamPush(List channels); + void updateGpsByDeviceIdForStreamPush(@Param("dataType") Integer dataType, List channels); @SelectProvider(type = ChannelProvider.class, method = "queryList") - List queryList(@Param("query") String query, @Param("online") Boolean online, @Param("hasRecordPlan") Boolean hasRecordPlan, @Param("channelType") Integer channelType); + List queryList(@Param("query") String query, @Param("online") Boolean online, + @Param("hasRecordPlan") Boolean hasRecordPlan, @Param("dataType") Integer dataType); @Update(value = {" ") List queryForRecordPlanForWebList(@Param("planId") Integer planId, @Param("query") String query, - @Param("channelType") Integer channelType, @Param("online") Boolean online, + @Param("dataType") Integer dataType, @Param("online") Boolean online, @Param("hasLink") Boolean hasLink); + @SelectProvider(type = ChannelProvider.class, method = "queryByDataId") + CommonGBChannel queryByDataId(@Param("dataType") Integer dataType, @Param("dataDeviceId") Integer dataDeviceId); + + @SelectProvider(type = ChannelProvider.class, method = "queryListByCivilCodeForUnusual") + List queryListByCivilCodeForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType); + + @SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualCivilCode") + List queryAllForUnusualCivilCode(); + + @SelectProvider(type = ChannelProvider.class, method = "queryListByParentForUnusual") + List queryListByParentForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType); + + @SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualParent") + List queryAllForUnusualParent(); + + @Update(value = {" "}) + void removeParentIdByChannelIds(List channelIdsForClear); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceChannelMapper.java index 068eb4b79..f700dad8f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceChannelMapper.java @@ -21,13 +21,13 @@ public interface DeviceChannelMapper { @Insert(""}) + " ") List queryChaneIdListByDeviceDbIds(List deviceDbIds); - @Delete("DELETE FROM wvp_device_channel WHERE device_db_id=#{deviceId}") - int cleanChannelsByDeviceId(@Param("deviceId") int deviceId); + @Delete("DELETE FROM wvp_device_channel WHERE data_type =1 and data_device_id=#{dataDeviceId}") + int cleanChannelsByDeviceId(@Param("dataDeviceId") int dataDeviceId); @Delete("DELETE FROM wvp_device_channel WHERE id=#{id}") int del(@Param("id") int id); @@ -141,8 +142,8 @@ public interface DeviceChannelMapper { " coalesce(dc.gb_business_group_id, dc.business_group_id) as business_group_id " + " from " + " wvp_device_channel dc " + - " LEFT JOIN wvp_device de ON dc.device_db_id = de.id " + - " WHERE 1=1" + + " LEFT JOIN wvp_device de ON dc.data_device_id = de.id " + + " WHERE dc.data_type = 1 " + " AND de.device_id = #{deviceId} " + " AND (dc.device_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%') " + " AND dc.parent_id=#{parentChannelId} " + @@ -155,7 +156,7 @@ public interface DeviceChannelMapper { " " + "ORDER BY dc.device_id ASC" + " "}) - List queryChannelsWithDeviceInfo(@Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List channelIds); + List queryChannelsWithDeviceInfo( @Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List channelIds); @Update(value = {"UPDATE wvp_device_channel SET stream_id=#{streamId} WHERE id=#{channelId}"}) void startPlay(@Param("channelId") Integer channelId, @Param("streamId") String streamId); @@ -172,9 +173,9 @@ public interface DeviceChannelMapper { " pgc.platform_id as platform_id,\n" + " pgc.catalog_id as catalog_id " + " FROM wvp_device_channel dc " + - " LEFT JOIN wvp_device de ON dc.device_db_id = de.id " + + " LEFT JOIN wvp_device de ON dc.data_device_id = de.id " + " LEFT JOIN wvp_platform_channel pgc on pgc.device_channel_id = dc.id " + - " WHERE 1=1 " + + " WHERE dc.data_type = 1 " + " " + "AND " + "(COALESCE(dc.gb_device_id, dc.device_id) LIKE concat('%',#{query},'%') " + @@ -195,14 +196,14 @@ public interface DeviceChannelMapper { @Insert(""}) int batchUpdateForNotify(List updateChannels); @@ -322,9 +325,9 @@ public interface DeviceChannelMapper { " set sub_count = (select *" + " from (select count(0)" + " from wvp_device_channel" + - " where device_db_id = #{deviceDbId} and parent_id = #{channelId}) as temp)" + - " where device_db_id = #{deviceDbId} and device_id = #{channelId}") - int updateChannelSubCount(@Param("deviceDbId") int deviceDbId, @Param("channelId") String channelId); + " where data_type = 1 and data_device_id = #{dataDeviceId} and parent_id = #{channelId}) as temp)" + + " where data_type = 1 and data_device_id = #{dataDeviceId} and device_id = #{channelId}") + int updateChannelSubCount(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId); @Update(value = {" "}) int batchUpdateStatus(List channels); @@ -427,7 +430,7 @@ public interface DeviceChannelMapper { ", latitude=#{item.latitude}" + ", gps_time=#{item.gpsTime}" + "WHERE id=#{item.id}" + - "WHERE device_db_id=#{item.deviceDbId} AND device_id=#{item.deviceId}" + + "WHERE data_type = #{item.dataType} and data_device_id=#{item.dataDeviceId} AND device_id=#{item.deviceId}" + "" + ""}) void batchUpdatePosition(List channelList); @@ -438,7 +441,7 @@ public interface DeviceChannelMapper { @Select(value = {" "}) - DeviceChannel getOneByDeviceIdForSource(@Param("deviceDbId") int deviceDbId, @Param("channelId") String channelId); + DeviceChannel getOneByDeviceIdForSource(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId); @Update(value = {"UPDATE wvp_device_channel SET stream_id=null WHERE id=#{channelId}"}) @@ -559,7 +562,7 @@ public interface DeviceChannelMapper { "") void updateStreamGPS(List gpsMsgInfoList); - @Update("UPDATE wvp_device_channel SET status=#{status} WHERE device_db_id=#{deviceDbId} AND device_id=#{deviceId}") + @Update("UPDATE wvp_device_channel SET status=#{status} WHERE data_type=#{dataType} and data_device_id=#{dataDeviceId} AND device_id=#{deviceId}") void updateStatus(DeviceChannel channel); @@ -568,7 +571,7 @@ public interface DeviceChannelMapper { " wvp_device_channel" + " SET update_time=#{updateTime}" + ", device_id=#{deviceId}" + - ", device_db_id=#{deviceDbId}" + + ", data_device_id=#{dataDeviceId}" + ", name=#{name}" + ", manufacturer=#{manufacturer}" + ", model=#{model}" + @@ -616,7 +619,7 @@ public interface DeviceChannelMapper { @Select(value = {" "}) - DeviceChannel getOneBySourceChannelId(int deviceDbId, String channelId); + DeviceChannel getOneBySourceChannelId(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java index abac64bb5..06a534821 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/DeviceMapper.java @@ -43,11 +43,12 @@ public interface DeviceMapper { "as_message_channel," + "geo_coord_sys," + "on_line," + + "server_id,"+ "media_server_id," + "broadcast_push_after_ack," + - "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.device_db_id= de.id) as channel_count "+ + "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.data_type = 1 and dc.data_device_id= de.id) as channel_count "+ " FROM wvp_device de WHERE de.device_id = #{deviceId}") - Device getDeviceByDeviceId(String deviceId); + Device getDeviceByDeviceId( @Param("deviceId") String deviceId); @Insert("INSERT INTO wvp_device (" + "device_id, " + @@ -66,7 +67,9 @@ public interface DeviceMapper { "expires," + "register_time," + "keepalive_time," + - "keepalive_interval_time," + + "heart_beat_interval," + + "heart_beat_count," + + "position_capability," + "create_time," + "update_time," + "charset," + @@ -78,6 +81,7 @@ public interface DeviceMapper { "as_message_channel,"+ "broadcast_push_after_ack,"+ "geo_coord_sys,"+ + "server_id,"+ "on_line"+ ") VALUES (" + "#{deviceId}," + @@ -96,7 +100,9 @@ public interface DeviceMapper { "#{expires}," + "#{registerTime}," + "#{keepaliveTime}," + - "#{keepaliveIntervalTime}," + + "#{heartBeatInterval}," + + "#{heartBeatCount}," + + "#{positionCapability}," + "#{createTime}," + "#{updateTime}," + "#{charset}," + @@ -108,6 +114,7 @@ public interface DeviceMapper { "#{asMessageChannel}," + "#{broadcastPushAfterAck}," + "#{geoCoordSys}," + + "#{serverId}," + "#{onLine}" + ")") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") @@ -128,8 +135,11 @@ public interface DeviceMapper { ", on_line=#{onLine}" + ", register_time=#{registerTime}" + ", keepalive_time=#{keepaliveTime}" + - ", keepalive_interval_time=#{keepaliveIntervalTime}" + + ", heart_beat_interval=#{heartBeatInterval}" + + ", position_capability=#{positionCapability}" + + ", heart_beat_count=#{heartBeatCount}" + ", expires=#{expires}" + + ", server_id=#{serverId}" + "WHERE device_id=#{deviceId}"+ " "}) int update(Device device); @@ -167,13 +177,13 @@ public interface DeviceMapper { "geo_coord_sys,"+ "on_line,"+ "media_server_id,"+ - "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.device_db_id= de.id) as channel_count " + + "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.data_type = #{dataType} and dc.data_device_id= de.id) as channel_count " + "FROM wvp_device de" + - " where de.on_line=${onLine}"+ + " where de.on_line=${online}"+ " order by de.create_time desc "+ " " ) - List getDevices(Boolean onLine); + List getDevices(@Param("dataType") Integer dataType, @Param("online") Boolean online); @Delete("DELETE FROM wvp_device WHERE device_id=#{deviceId}") int del(String deviceId); @@ -207,9 +217,43 @@ public interface DeviceMapper { "as_message_channel,"+ "broadcast_push_after_ack,"+ "geo_coord_sys,"+ + "server_id,"+ "on_line"+ " FROM wvp_device WHERE on_line = true") List getOnlineDevices(); + @Select("SELECT " + + "id, " + + "device_id, " + + "coalesce(custom_name, name) as name, " + + "password, " + + "manufacturer, " + + "model, " + + "firmware, " + + "transport," + + "stream_mode," + + "ip," + + "sdp_ip,"+ + "local_ip,"+ + "port,"+ + "host_address,"+ + "expires,"+ + "register_time,"+ + "keepalive_time,"+ + "create_time,"+ + "update_time,"+ + "charset,"+ + "subscribe_cycle_for_catalog,"+ + "subscribe_cycle_for_mobile_position,"+ + "mobile_position_submission_interval,"+ + "subscribe_cycle_for_alarm,"+ + "ssrc_check,"+ + "as_message_channel,"+ + "broadcast_push_after_ack,"+ + "geo_coord_sys,"+ + "server_id,"+ + "on_line"+ + " FROM wvp_device WHERE on_line = true and server_id = #{serverId}") + List getOnlineDevicesByServerId(@Param("serverId") String serverId); @Select("SELECT " + "id,"+ @@ -247,9 +291,8 @@ public interface DeviceMapper { @Update(value = {" "}) @@ -269,6 +312,7 @@ public interface DeviceMapper { "geo_coord_sys,"+ "on_line,"+ "stream_mode," + + "server_id," + "media_server_id"+ ") VALUES (" + "#{deviceId}," + @@ -284,6 +328,7 @@ public interface DeviceMapper { "#{geoCoordSys}," + "#{onLine}," + "#{streamMode}," + + "#{serverId}," + "#{mediaServerId}" + ")") void addCustomDevice(Device device); @@ -326,7 +371,8 @@ public interface DeviceMapper { "geo_coord_sys,"+ "on_line,"+ "media_server_id,"+ - "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.device_db_id= de.id) as channel_count " + + "server_id,"+ + "(SELECT count(0) FROM wvp_device_channel dc WHERE dc.data_type = #{dataType} and dc.data_device_id= de.id) as channel_count " + " FROM wvp_device de" + " where 1 = 1 "+ " AND de.on_line=${status}"+ @@ -337,7 +383,7 @@ public interface DeviceMapper { " " + " order by create_time desc "+ " ") - List getDeviceList(@Param("query") String query, @Param("status") Boolean status); + List getDeviceList(@Param("dataType") Integer dataType, @Param("query") String query, @Param("status") Boolean status); @Select("select * from wvp_device_channel where id = #{id}") DeviceChannel getRawChannel(@Param("id") int id); @@ -345,10 +391,23 @@ public interface DeviceMapper { @Select("select * from wvp_device where id = #{id}") Device query(@Param("id") Integer id); - @Select("select wd.* from wvp_device wd left join wvp_device_channel wdc on wd.id = wdc.device_db_id where wdc.id = #{channelId}") - Device queryByChannelId(@Param("channelId") Integer channelId); + @Select("select wd.* from wvp_device wd left join wvp_device_channel wdc on wdc.data_type = #{dataType} and wd.id = wdc.data_device_id where wdc.id = #{channelId}") + Device queryByChannelId(@Param("dataType") Integer dataType, @Param("channelId") Integer channelId); - @Select("select wd.* from wvp_device wd left join wvp_device_channel wdc on wd.id = wdc.device_db_id where wdc.device_id = #{channelDeviceId}") - Device getDeviceBySourceChannelDeviceId(@Param("channelDeviceId") String channelDeviceId); + @Select("select wd.* from wvp_device wd left join wvp_device_channel wdc on wdc.data_type = #{dataType} and wd.id = wdc.data_device_id where wdc.device_id = #{channelDeviceId}") + Device getDeviceBySourceChannelDeviceId(@Param("dataType") Integer dataType, @Param("channelDeviceId") String channelDeviceId); + @Update(value = {" "}) + void updateSubscribeCatalog(Device device); + + @Update(value = {" "}) + void updateSubscribeMobilePosition(Device device); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java index 5e24201ea..c69a32d5c 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/PlatformChannelMapper.java @@ -58,17 +58,18 @@ public interface PlatformChannelMapper { "where dc.channel_type = 0 and dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}") List queryDeviceInfoByPlatformIdAndChannelId(@Param("platformId") String platformId, @Param("channelId") String channelId); - @Select("SELECT pgc.platform_id from wvp_platform_channel pgc left join wvp_device_channel dc on dc.id = pgc.device_channel_id WHERE dc.channel_type = 0 and dc.device_id=#{channelId}") - List queryParentPlatformByChannelId(@Param("channelId") String channelId); + @Select(" SELECT wp.* from wvp_platform_channel pgc " + + " left join wvp_device_channel dc on dc.id = pgc.device_channel_id " + + " left join wvp_platform wp on wp.id = pgc.platform_id" + + " WHERE dc.channel_type = 0 and dc.device_id=#{channelId}") + List queryParentPlatformByChannelId(@Param("channelId") String channelId); @Select("") List queryForPlatformForWebList(@Param("platformId") Integer platformId, @Param("query") String query, - @Param("channelType") Integer channelType, @Param("online") Boolean online, + @Param("dataType") Integer dataType, @Param("online") Boolean online, @Param("hasShare") Boolean hasShare); @Select("select\n" + " wdc.id as gb_id,\n" + - " wdc.device_db_id as gb_device_db_id,\n" + - " wdc.stream_push_id,\n" + - " wdc.stream_proxy_id,\n" + - " wdc.jt_channel_id,\n" + + " wdc.data_type,\n" + + " wdc.data_device_id,\n" + " wdc.create_time,\n" + " wdc.update_time,\n" + " coalesce(wpgc.custom_device_id, wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" + @@ -212,10 +208,8 @@ public interface PlatformChannelMapper { @Select("") List queryList(@Param("query") String query); - @Select("SELECT * FROM wvp_platform WHERE enable=#{enable} ") - List getEnableParentPlatformList(boolean enable); + @Select("SELECT * FROM wvp_platform WHERE server_id=#{serverId} and enable=#{enable} ") + List queryEnableParentPlatformList(@Param("serverId") String serverId, @Param("enable") boolean enable); @Select("SELECT * FROM wvp_platform WHERE enable=true and as_message_channel=true") List queryEnablePlatformListWithAsMessageChannel(); @@ -91,7 +92,9 @@ public interface PlatformMapper { @Update("UPDATE wvp_platform SET status=#{online} WHERE server_gb_id=#{platformGbID}" ) int updateStatus(@Param("platformGbID") String platformGbID, @Param("online") boolean online); - @Select("SELECT * FROM wvp_platform WHERE enable=true") - List queryEnablePlatformList(); + @Select("SELECT server_id FROM wvp_platform WHERE enable=true and server_id != #{serverId} group by server_id") + List queryServerIdsWithEnableAndNotInServer(@Param("serverId") String serverId); + @Select("SELECT * FROM wvp_platform WHERE server_id = #{serverId}") + List queryByServerId(@Param("serverId") String serverId); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java index f31146721..c9b9cfac8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/RegionMapper.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.dao; +import com.genersoft.iot.vmp.common.CivilCodePo; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Region; import com.genersoft.iot.vmp.gb28181.bean.RegionTree; @@ -179,4 +180,12 @@ public interface RegionMapper { " ") Set queryNotShareRegionForPlatformByRegionList(Set allRegion, @Param("platformId") Integer platformId); + + @Select(" ") + Set queryInCivilCodePoList(List civilCodePoList); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java index 7c2395f6d..f2df8ad2e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/ChannelProvider.java @@ -12,10 +12,8 @@ public class ChannelProvider { public final static String BASE_SQL = "select\n" + " id as gb_id,\n" + - " device_db_id as gb_device_db_id,\n" + - " stream_push_id,\n" + - " stream_proxy_id,\n" + - " jt_channel_id,\n" + + " data_type,\n" + + " data_device_id,\n" + " create_time,\n" + " update_time,\n" + " record_plan_id,\n" + @@ -55,14 +53,56 @@ public class ChannelProvider { " coalesce(gb_svc_time_support_mode,svc_time_support_mode) as gb_svc_time_support_mode\n" + " from wvp_device_channel\n" ; - + + public final static String BASE_SQL_TABLE_NAME = "select\n" + + " wdc.id as gb_id,\n" + + " wdc.data_type,\n" + + " wdc.data_device_id,\n" + + " wdc.create_time,\n" + + " wdc.update_time,\n" + + " wdc.record_plan_id,\n" + + " coalesce(wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" + + " coalesce(wdc.gb_name, wdc.name) as gb_name,\n" + + " coalesce(wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" + + " coalesce(wdc.gb_model, wdc.model) as gb_model,\n" + + " coalesce(wdc.gb_owner, wdc.owner) as gb_owner,\n" + + " coalesce(wdc.gb_civil_code, wdc.civil_code) as gb_civil_code,\n" + + " coalesce(wdc.gb_block, wdc.block) as gb_block,\n" + + " coalesce(wdc.gb_address, wdc.address) as gb_address,\n" + + " coalesce(wdc.gb_parental, wdc.parental) as gb_parental,\n" + + " coalesce(wdc.gb_parent_id, wdc.parent_id) as gb_parent_id,\n" + + " coalesce(wdc.gb_safety_way, wdc.safety_way) as gb_safety_way,\n" + + " coalesce(wdc.gb_register_way, wdc.register_way) as gb_register_way,\n" + + " coalesce(wdc.gb_cert_num, wdc.cert_num) as gb_cert_num,\n" + + " coalesce(wdc.gb_certifiable, wdc.certifiable) as gb_certifiable,\n" + + " coalesce(wdc.gb_err_code, wdc.err_code) as gb_err_code,\n" + + " coalesce(wdc.gb_end_time, wdc.end_time) as gb_end_time,\n" + + " coalesce(wdc.gb_secrecy, wdc.secrecy) as gb_secrecy,\n" + + " coalesce(wdc.gb_ip_address, wdc.ip_address) as gb_ip_address,\n" + + " coalesce(wdc.gb_port, wdc.port) as gb_port,\n" + + " coalesce(wdc.gb_password, wdc.password) as gb_password,\n" + + " coalesce(wdc.gb_status, wdc.status) as gb_status,\n" + + " coalesce(wdc.gb_longitude, wdc.longitude) as gb_longitude,\n" + + " coalesce(wdc.gb_latitude, wdc.latitude) as gb_latitude,\n" + + " coalesce(wdc.gb_ptz_type, wdc.ptz_type) as gb_ptz_type,\n" + + " coalesce(wdc.gb_position_type, wdc.position_type) as gb_position_type,\n" + + " coalesce(wdc.gb_room_type, wdc.room_type) as gb_room_type,\n" + + " coalesce(wdc.gb_use_type, wdc.use_type) as gb_use_type,\n" + + " coalesce(wdc.gb_supply_light_type, wdc.supply_light_type) as gb_supply_light_type,\n" + + " coalesce(wdc.gb_direction_type, wdc.direction_type) as gb_direction_type,\n" + + " coalesce(wdc.gb_resolution, wdc.resolution) as gb_resolution,\n" + + " coalesce(wdc.gb_business_group_id, wdc.business_group_id) as gb_business_group_id,\n" + + " coalesce(wdc.gb_download_speed, wdc.download_speed) as gb_download_speed,\n" + + " coalesce(wdc.gb_svc_space_support_mod, wdc.svc_space_support_mod) as gb_svc_space_support_mod,\n" + + " coalesce(wdc.gb_svc_time_support_mode, wdc.svc_time_support_mode) as gb_svc_time_support_mode\n" + + " from wvp_device_channel wdc\n" + ; + private final static String BASE_SQL_FOR_PLATFORM = "select\n" + " wdc.id as gb_id,\n" + - " wdc.device_db_id as gb_device_db_id,\n" + - " wdc.stream_push_id,\n" + - " wdc.stream_proxy_id,\n" + - " wdc.jt_channel_id,\n" + + " wdc.data_type,\n" + + " wdc.data_device_id,\n" + " wdc.create_time,\n" + " wdc.update_time,\n" + " coalesce(wpgc.custom_device_id, wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" + @@ -111,15 +151,10 @@ public class ChannelProvider { return BASE_SQL + " where channel_type = 0 and id = #{gbId}"; } - public String queryByStreamPushId(Map params ){ - return BASE_SQL + " where channel_type = 0 and stream_push_id = #{streamPushId}"; + public String queryByDataId(Map params ){ + return BASE_SQL + " where channel_type = 0 and data_type = #{dataType} and data_device_id = #{dataDeviceId}"; } - public String queryByStreamProxyId(Map params ){ - return BASE_SQL + " where channel_type = 0 and stream_proxy_id = #{streamProxyId}"; - } - - public String queryListByCivilCode(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(BASE_SQL); @@ -140,16 +175,8 @@ public class ChannelProvider { }else { sqlBuild.append(" AND coalesce(gb_civil_code, civil_code) is null"); } - if (params.get("channelType") != null) { - if ((Integer)params.get("channelType") == 0) { - sqlBuild.append(" AND device_db_id is not null"); - }else if ((Integer)params.get("channelType") == 1) { - sqlBuild.append(" AND stream_push_id is not null"); - }else if ((Integer)params.get("channelType") == 2) { - sqlBuild.append(" AND stream_proxy_id is not null"); - }else if ((Integer)params.get("channelType") == 4) { - sqlBuild.append(" AND jt_channel_id is not null"); - } + if (params.get("dataType") != null) { + sqlBuild.append(" AND data_type = #{dataType}"); } return sqlBuild.toString(); } @@ -174,17 +201,8 @@ public class ChannelProvider { }else { sqlBuild.append(" AND coalesce(gb_parent_id, parent_id) is null"); } - - if (params.get("channelType") != null) { - if ((Integer)params.get("channelType") == 0) { - sqlBuild.append(" AND device_db_id is not null"); - }else if ((Integer)params.get("channelType") == 1) { - sqlBuild.append(" AND stream_push_id is not null"); - }else if ((Integer)params.get("channelType") == 2) { - sqlBuild.append(" AND stream_proxy_id is not null"); - }else if ((Integer)params.get("channelType") == 4) { - sqlBuild.append(" AND jt_channel_id is not null"); - } + if (params.get("dataType") != null) { + sqlBuild.append(" AND data_type = #{dataType}"); } return sqlBuild.toString(); } @@ -207,15 +225,8 @@ public class ChannelProvider { if (params.get("hasRecordPlan") != null && (Boolean)params.get("hasRecordPlan")) { sqlBuild.append(" AND record_plan_id > 0"); } - - if (params.get("channelType") != null) { - if ((Integer)params.get("channelType") == 0) { - sqlBuild.append(" AND device_db_id is not null"); - }else if ((Integer)params.get("channelType") == 1) { - sqlBuild.append(" AND stream_push_id is not null"); - }else if ((Integer)params.get("channelType") == 2) { - sqlBuild.append(" AND stream_proxy_id is not null"); - } + if (params.get("dataType") != null) { + sqlBuild.append(" AND data_type = #{dataType}"); } return sqlBuild.toString(); } @@ -259,7 +270,7 @@ public class ChannelProvider { public String queryByGbDeviceIds(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(BASE_SQL); - sqlBuild.append("where channel_type = 0 and device_db_id in ( "); + sqlBuild.append("where channel_type = 0 and data_type = #{dataType} and data_device_id in ( "); Collection ids = (Collection)params.get("deviceIds"); boolean first = true; @@ -362,7 +373,7 @@ public class ChannelProvider { StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(BASE_SQL); - sqlBuild.append(" where channel_type = 0 and stream_push_id in ( "); + sqlBuild.append(" where channel_type = 0 and data_type = #{dataType} and data_device_id in ( "); Collection ids = (Collection)params.get("streamPushList"); boolean first = true; for (StreamPush streamPush : ids) { @@ -397,4 +408,68 @@ public class ChannelProvider { sqlBuild.append(" where wpgc.platform_id = #{platformId} and coalesce(wpgc.custom_civil_code, wdc.gb_civil_code, wdc.civil_code) = #{civilCode}"); return sqlBuild.toString() ; } + + public String queryListByCivilCodeForUnusual(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append(BASE_SQL_TABLE_NAME); + sqlBuild.append(" left join (select wcr.device_id from wvp_common_region wcr) temp on temp.device_id = coalesce(wdc.gb_civil_code, wdc.civil_code)" + + " where coalesce(wdc.gb_civil_code, wdc.civil_code) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + if (params.get("query") != null) { + sqlBuild.append(" AND (coalesce(wdc.gb_device_id, wdc.device_id) LIKE concat('%',#{query},'%') escape '/'" + + " OR coalesce(wdc.gb_name, wdc.name) LIKE concat('%',#{query},'%') escape '/' )") + ; + } + if (params.get("online") != null && (Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'ON'"); + } + if (params.get("online") != null && !(Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'OFF'"); + } + if (params.get("dataType") != null) { + sqlBuild.append(" AND wdc.data_type = #{dataType}"); + } + return sqlBuild.toString(); + } + + public String queryListByParentForUnusual(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append(BASE_SQL_TABLE_NAME); + sqlBuild.append(" left join (select wcg.device_id from wvp_common_group wcg) temp on temp.device_id = coalesce(wdc.gb_parent_id, wdc.parent_id)" + + " where coalesce(wdc.gb_parent_id, wdc.parent_id) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + if (params.get("query") != null) { + sqlBuild.append(" AND (coalesce(wdc.gb_device_id, wdc.device_id) LIKE concat('%',#{query},'%') escape '/'" + + " OR coalesce(wdc.gb_name, wdc.name) LIKE concat('%',#{query},'%') escape '/' )") + ; + } + if (params.get("online") != null && (Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'ON'"); + } + if (params.get("online") != null && !(Boolean)params.get("online")) { + sqlBuild.append(" AND coalesce(wdc.gb_status, wdc.status) = 'OFF'"); + } + if (params.get("dataType") != null) { + sqlBuild.append(" AND wdc.data_type = #{dataType}"); + } + return sqlBuild.toString(); + } + + public String queryAllForUnusualCivilCode(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append("select wdc.id from wvp_device_channel wdc "); + sqlBuild.append(" left join (select wcr.device_id from wvp_common_region wcr) temp on temp.device_id = coalesce(wdc.gb_civil_code, wdc.civil_code)" + + " where coalesce(wdc.gb_civil_code, wdc.civil_code) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + return sqlBuild.toString(); + } + + public String queryAllForUnusualParent(Map params ){ + StringBuilder sqlBuild = new StringBuilder(); + sqlBuild.append("select wdc.id from wvp_device_channel wdc "); + sqlBuild.append(" left join (select wcg.device_id from wvp_common_group wcg) temp on temp.device_id = coalesce(wdc.gb_parent_id, wdc.parent_id)" + + " where coalesce(wdc.gb_parent_id, wdc.parent_id) is not null and temp.device_id is null "); + sqlBuild.append(" AND wdc.channel_type = 0 "); + return sqlBuild.toString(); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java index 719ad2845..eece8399e 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/provider/DeviceChannelProvider.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.dao.provider; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import org.springframework.util.ObjectUtils; import java.util.List; @@ -10,7 +11,7 @@ public class DeviceChannelProvider { public String getBaseSelectSql(){ return "SELECT " + " dc.id,\n" + - " dc.device_db_id,\n" + + " dc.data_device_id,\n" + " dc.create_time,\n" + " dc.update_time,\n" + " dc.sub_count,\n" + @@ -60,7 +61,7 @@ public class DeviceChannelProvider { public String queryChannels(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(getBaseSelectSql()); - sqlBuild.append(" where dc.device_db_id = #{deviceDbId} "); + sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId} "); if (params.get("businessGroupId") != null ) { sqlBuild.append(" AND coalesce(dc.gb_business_group_id, dc.business_group_id)=#{businessGroupId} AND coalesce(dc.gb_parent_id, dc.parent_id) is null"); }else if (params.get("parentChannelId") != null ) { @@ -107,14 +108,14 @@ public class DeviceChannelProvider { public String queryChannelsByDeviceDbId(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(getBaseSelectSql()); - sqlBuild.append(" where dc.device_db_id = #{deviceDbId}"); + sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId}"); return sqlBuild.toString(); } public String queryAllChannels(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(getBaseSelectSql()); - sqlBuild.append(" where dc.device_db_id = #{deviceDbId}"); + sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id = #{dataDeviceId}"); return sqlBuild.toString(); } @@ -128,33 +129,25 @@ public class DeviceChannelProvider { public String getOneByDeviceId(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(getBaseSelectSql()); - sqlBuild.append(" where dc.device_db_id=#{deviceDbId} and coalesce(dc.gb_device_id, dc.device_id) = #{channelId}"); + sqlBuild.append(" where data_type = " + ChannelDataType.GB28181.value + " and dc.data_device_id=#{dataDeviceId} and coalesce(dc.gb_device_id, dc.device_id) = #{channelId}"); return sqlBuild.toString(); } public String queryByDeviceId(Map params ){ - return getBaseSelectSql() + " where channel_type = 0 and coalesce(gb_device_id, device_id) = #{gbDeviceId}"; + return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181.value + " and channel_type = 0 and coalesce(gb_device_id, device_id) = #{gbDeviceId}"; } public String queryById(Map params ){ - return getBaseSelectSql() + " where channel_type = 0 and id = #{gbId}"; - } - - public String queryByStreamPushId(Map params ){ - return getBaseSelectSql() + " where channel_type = 0 and stream_push_id = #{streamPushId}"; - } - - public String queryByStreamProxyId(Map params ){ - return getBaseSelectSql() + " where channel_type = 0 and stream_proxy_id = #{streamProxyId}"; + return getBaseSelectSql() + " where data_type = " + ChannelDataType.GB28181.value + " and channel_type = 0 and id = #{gbId}"; } public String queryList(Map params ){ StringBuilder sqlBuild = new StringBuilder(); sqlBuild.append(getBaseSelectSql()); - sqlBuild.append(" where channel_type = 0 "); + sqlBuild.append(" where channel_type = 0 and data_type = " + ChannelDataType.GB28181.value); if (params.get("query") != null) { sqlBuild.append(" AND (coalesce(gb_device_id, device_id) LIKE concat('%',#{query},'%')" + " OR coalesce(gb_name, name) LIKE concat('%',#{query},'%') )") diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java index 7d4c876a9..9aa75b712 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/EventPublisher.java @@ -1,19 +1,21 @@ package com.genersoft.iot.vmp.gb28181.event; -import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; +import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; +import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEvent; -import com.genersoft.iot.vmp.gb28181.event.device.RequestTimeoutEvent; -import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.mobilePosition.MobilePositionEvent; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOfflineEvent; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerOnlineEvent; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Component; -import javax.sip.TimeoutEvent; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -29,7 +31,13 @@ public class EventPublisher { @Autowired private ApplicationEventPublisher applicationEventPublisher; - + + @Autowired + private UserSetting userSetting; + + @Autowired + private IRedisRpcService redisRpcService; + /** * 设备报警事件 * @param deviceAlarm @@ -53,27 +61,25 @@ public class EventPublisher { } - public void catalogEventPublish(Integer platformId, CommonGBChannel deviceChannel, String type) { + public void catalogEventPublish(Platform platform, CommonGBChannel deviceChannel, String type) { List deviceChannelList = new ArrayList<>(); deviceChannelList.add(deviceChannel); - catalogEventPublish(platformId, deviceChannelList, type); + catalogEventPublish(platform, deviceChannelList, type); } - - public void requestTimeOut(TimeoutEvent timeoutEvent) { - RequestTimeoutEvent requestTimeoutEvent = new RequestTimeoutEvent(this); - requestTimeoutEvent.setTimeoutEvent(timeoutEvent); - applicationEventPublisher.publishEvent(requestTimeoutEvent); + public void catalogEventPublish(Platform platform, List deviceChannels, String type) { + catalogEventPublish(platform, deviceChannels, type, true); } - - - /** - * - * @param platformId - * @param deviceChannels - * @param type - */ - public void catalogEventPublish(Integer platformId, List deviceChannels, String type) { + public void catalogEventPublish(Platform platform, List deviceChannels, String type, boolean share) { + if (platform != null && !userSetting.getServerId().equals(platform.getServerId())) { + // 指定了上级平台的推送,则发送到指定的设备,未指定的则全部发送, 接收后各自处理自己的 + CatalogEvent outEvent = new CatalogEvent(this); + outEvent.setChannels(deviceChannels); + outEvent.setType(type); + outEvent.setPlatform(platform); + redisRpcService.catalogEventPublish(platform.getServerId(), outEvent); + return; + } CatalogEvent outEvent = new CatalogEvent(this); List channels = new ArrayList<>(); if (deviceChannels.size() > 1) { @@ -90,20 +96,19 @@ public class EventPublisher { } outEvent.setChannels(channels); outEvent.setType(type); - outEvent.setPlatformId(platformId); + outEvent.setPlatform(platform); applicationEventPublisher.publishEvent(outEvent); + if (platform == null && share) { + // 如果没指定上级平台,则推送消息到所有在线的wvp处理自己含有的平台的目录更新 + redisRpcService.catalogEventPublish(null, outEvent); + } } - public void mobilePositionEventPublish(MobilePosition mobilePosition) { MobilePositionEvent event = new MobilePositionEvent(this); event.setMobilePosition(mobilePosition); applicationEventPublisher.publishEvent(event); } - public void recordEndEventPush(RecordInfo recordInfo) { - RecordEndEvent outEvent = new RecordEndEvent(this); - outEvent.setRecordInfo(recordInfo); - applicationEventPublisher.publishEvent(outEvent); - } + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/MessageSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/MessageSubscribe.java new file mode 100755 index 000000000..f86c87867 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/MessageSubscribe.java @@ -0,0 +1,73 @@ +package com.genersoft.iot.vmp.gb28181.event; + +import com.genersoft.iot.vmp.gb28181.event.sip.MessageEvent; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.DelayQueue; + +/** + * @author lin + */ +@Slf4j +@Component +public class MessageSubscribe { + + private final Map> subscribes = new ConcurrentHashMap<>(); + + private final DelayQueue> delayQueue = new DelayQueue<>(); + + @Scheduled(fixedDelay = 200) //每200毫秒执行 + public void execute(){ + while (!delayQueue.isEmpty()) { + try { + MessageEvent take = delayQueue.take(); + // 出现超时异常 + if(take.getCallback() != null) { + take.getCallback().run(ErrorCode.ERROR486.getCode(), "消息超时未回复", null); + } + subscribes.remove(take.getKey()); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + + + public void addSubscribe(MessageEvent event) { + MessageEvent messageEvent = subscribes.get(event.getKey()); + if (messageEvent != null) { + subscribes.remove(event.getKey()); + delayQueue.remove(messageEvent); + } + subscribes.put(event.getKey(), event); + delayQueue.offer(event); + } + + public MessageEvent getSubscribe(String key) { + return subscribes.get(key); + } + + public void removeSubscribe(String key) { + if(key == null){ + return; + } + MessageEvent messageEvent = subscribes.get(key); + if (messageEvent != null) { + subscribes.remove(key); + delayQueue.remove(messageEvent); + } + } + + public boolean isEmpty(){ + return subscribes.isEmpty(); + } + + public Integer size() { + return subscribes.size(); + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java index a2034c726..027970038 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/SipSubscribe.java @@ -29,24 +29,24 @@ public class SipSubscribe { private final DelayQueue delayQueue = new DelayQueue<>(); + @Scheduled(fixedDelay = 200) //每200毫秒执行 public void execute(){ - if (delayQueue.isEmpty()) { - return; - } - try { - SipEvent take = delayQueue.take(); - // 出现超时异常 - if(take.getErrorEvent() != null) { - EventResult eventResult = new EventResult<>(); - eventResult.type = EventResultType.timeout; - eventResult.msg = "消息超时未回复"; - eventResult.statusCode = -1024; - take.getErrorEvent().response(eventResult); + while (!delayQueue.isEmpty()) { + try { + SipEvent take = delayQueue.take(); + // 出现超时异常 + if(take.getErrorEvent() != null) { + EventResult eventResult = new EventResult<>(); + eventResult.type = EventResultType.timeout; + eventResult.msg = "消息超时未回复"; + eventResult.statusCode = -1024; + take.getErrorEvent().response(eventResult); + } + subscribes.remove(take.getKey()); + } catch (InterruptedException e) { + throw new RuntimeException(e); } - subscribes.remove(take.getKey()); - } catch (InterruptedException e) { - throw new RuntimeException(e); } } @@ -78,7 +78,9 @@ public class SipSubscribe { // 消息发送失败 cmdSendFailEvent, // 消息发送失败 - failedToGetPort + failedToGetPort, + // 收到失败的回复 + failedResult } public static class EventResult{ diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java deleted file mode 100755 index c4d3baba8..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEvent.java +++ /dev/null @@ -1,25 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.event.device; - -import org.springframework.context.ApplicationEvent; - -import javax.sip.TimeoutEvent; - -/** - * @author lin - */ -public class RequestTimeoutEvent extends ApplicationEvent { - public RequestTimeoutEvent(Object source) { - super(source); - } - - - private TimeoutEvent timeoutEvent; - - public TimeoutEvent getTimeoutEvent() { - return timeoutEvent; - } - - public void setTimeoutEvent(TimeoutEvent timeoutEvent) { - this.timeoutEvent = timeoutEvent; - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java deleted file mode 100755 index 5f83e6e9b..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/device/RequestTimeoutEventImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.event.device; - -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.service.IDeviceService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationListener; -import org.springframework.stereotype.Component; - -import javax.sip.ClientTransaction; -import javax.sip.address.SipURI; -import javax.sip.message.Request; - -/** - * @author lin - */ -@Component -public class RequestTimeoutEventImpl implements ApplicationListener { - - @Autowired - private IDeviceService deviceService; - - @Override - public void onApplicationEvent(RequestTimeoutEvent event) { - ClientTransaction clientTransaction = event.getTimeoutEvent().getClientTransaction(); - if (clientTransaction != null) { - Request request = clientTransaction.getRequest(); - if (request != null) { - String host = ((SipURI) request.getRequestURI()).getHost(); - int port = ((SipURI) request.getRequestURI()).getPort(); - Device device = deviceService.getDeviceByHostAndPort(host, port); - if (device == null) { - return; - } - deviceService.offline(device.getDeviceId(), "等待消息超时"); - } - - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEndEvent.java similarity index 54% rename from src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEndEvent.java index cfd2985c5..4788eb622 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEndEvent.java @@ -1,7 +1,8 @@ package com.genersoft.iot.vmp.gb28181.event.record; -import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import lombok.Getter; +import lombok.Setter; import org.springframework.context.ApplicationEvent; /** @@ -9,24 +10,18 @@ import org.springframework.context.ApplicationEvent; * @author: pan * @data: 2022-02-23 */ - -public class RecordEndEvent extends ApplicationEvent { +@Setter +@Getter +public class RecordInfoEndEvent extends ApplicationEvent { /** * */ private static final long serialVersionUID = 1L; - public RecordEndEvent(Object source) { + public RecordInfoEndEvent(Object source) { super(source); } private RecordInfo recordInfo; - public RecordInfo getRecordInfo() { - return recordInfo; - } - - public void setRecordInfo(RecordInfo recordInfo) { - this.recordInfo = recordInfo; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEvent.java new file mode 100755 index 000000000..d78a22b28 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEvent.java @@ -0,0 +1,27 @@ +package com.genersoft.iot.vmp.gb28181.event.record; + +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +/** + * @description: 录像查询结束时间 + * @author: pan + * @data: 2022-02-23 + */ + +@Setter +@Getter +public class RecordInfoEvent extends ApplicationEvent { + /** + * + */ + private static final long serialVersionUID = 1L; + + public RecordInfoEvent(Object source) { + super(source); + } + + private RecordInfo recordInfo; +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEventListener.java similarity index 85% rename from src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java rename to src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEventListener.java index 411b54d5c..f2a0986d6 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordEndEventListener.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/record/RecordInfoEventListener.java @@ -15,15 +15,15 @@ import java.util.concurrent.ConcurrentHashMap; */ @Slf4j @Component -public class RecordEndEventListener implements ApplicationListener { +public class RecordInfoEventListener implements ApplicationListener { - private Map handlerMap = new ConcurrentHashMap<>(); + private final Map handlerMap = new ConcurrentHashMap<>(); public interface RecordEndEventHandler{ void handler(RecordInfo recordInfo); } @Override - public void onApplicationEvent(RecordEndEvent event) { + public void onApplicationEvent(RecordInfoEvent event) { String deviceId = event.getRecordInfo().getDeviceId(); String channelId = event.getRecordInfo().getChannelId(); int count = event.getRecordInfo().getCount(); @@ -45,9 +45,6 @@ public class RecordEndEventListener implements ApplicationListener implements Delayed { + /** + * 超时时间(单位: 毫秒) + */ + private long delay; + + private String cmdType; + + private String sn; + + private String deviceId; + + private String result; + + private T t; + + private ErrorCallback callback; + + @Override + public long getDelay(@NotNull TimeUnit unit) { + return unit.convert(delay - System.currentTimeMillis(), TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(@NotNull Delayed o) { + return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS)); + } + + public String getKey(){ + return cmdType + sn; + } + + public static MessageEvent getInstance(String cmdType, String sn, String deviceId, Long delay, ErrorCallback callback){ + MessageEvent messageEvent = new MessageEvent<>(); + messageEvent.cmdType = cmdType; + messageEvent.sn = sn; + messageEvent.deviceId = deviceId; + messageEvent.callback = callback; + if (delay == null) { + messageEvent.delay = System.currentTimeMillis() + 1000; + }else { + messageEvent.delay = System.currentTimeMillis() + delay; + } + return messageEvent; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java index e6af35caf..be20a54e2 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/sip/SipEvent.java @@ -32,13 +32,13 @@ public class SipEvent implements Delayed { sipEvent.setKey(key); sipEvent.setOkEvent(okEvent); sipEvent.setErrorEvent(errorEvent); - sipEvent.setDelay(delay); + sipEvent.setDelay(System.currentTimeMillis() + delay); return sipEvent; } @Override public long getDelay(@NotNull TimeUnit unit) { - return unit.convert(delay, TimeUnit.MILLISECONDS); + return unit.convert(delay - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java index 339781d4c..d0d2122dc 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEvent.java @@ -1,12 +1,15 @@ package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.Platform; import lombok.Getter; import lombok.Setter; import org.springframework.context.ApplicationEvent; import java.util.List; +@Setter +@Getter public class CatalogEvent extends ApplicationEvent { public CatalogEvent(Object source) { @@ -48,16 +51,10 @@ public class CatalogEvent extends ApplicationEvent { */ public static final String UPDATE = "UPDATE"; - @Setter - @Getter private List channels; - @Setter - @Getter private String type; - @Setter - @Getter - private Integer platformId; + private Platform platform; } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java index 28a422648..08a329022 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/event/subscribe/catalog/CatalogEventLister.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.event.subscribe.catalog; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder; @@ -7,6 +8,7 @@ import com.genersoft.iot.vmp.gb28181.bean.SubscribeInfo; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationListener; @@ -15,10 +17,7 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.SipException; import java.text.ParseException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * catalog事件 @@ -30,9 +29,6 @@ public class CatalogEventLister implements ApplicationListener { @Autowired private IPlatformChannelService platformChannelService; - @Autowired - private IPlatformService platformService; - @Autowired private ISIPCommanderForPlatform sipCommanderFroPlatform; @@ -46,11 +42,8 @@ public class CatalogEventLister implements ApplicationListener { Map> parentPlatformMap = new HashMap<>(); Map channelMap = new HashMap<>(); - if (event.getPlatformId() != null) { - parentPlatform = platformService.queryOne(event.getPlatformId()); - if (parentPlatform == null) { - return; - } + if (event.getPlatform() != null) { + parentPlatform = event.getPlatform(); subscribe = subscribeHolder.getCatalogSubscribe(parentPlatform.getServerGBId()); if (subscribe == null) { return; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceChannelService.java index bb21e3214..6cc39f760 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceChannelService.java @@ -1,13 +1,18 @@ package com.genersoft.iot.vmp.gb28181.service; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.common.enums.DeviceControlType; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; import com.github.pagehelper.PageInfo; +import org.dom4j.Element; +import javax.validation.constraints.NotNull; import java.util.List; /** @@ -125,4 +130,11 @@ public interface IDeviceChannelService { List queryChaneListByDeviceDbId(Integer deviceDbId); List queryChaneIdListByDeviceDbIds(List deviceDbId); + + void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback callback); + + void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback object); + + void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback object); + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java index 0812f8cfa..7447a830a 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IDeviceService.java @@ -1,10 +1,10 @@ package com.genersoft.iot.vmp.gb28181.service; import com.genersoft.iot.vmp.common.CommonCallback; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo; -import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.github.pagehelper.PageInfo; import java.util.List; @@ -86,7 +86,7 @@ public interface IDeviceService { * 获取所有在线设备 * @return 设备列表 */ - List getAllOnlineDevice(); + List getAllOnlineDevice(String serverId); List getAllByStatus(Boolean status); @@ -101,7 +101,7 @@ public interface IDeviceService { * 检查设备状态 * @param device 设备信息 */ - void checkDeviceStatus(Device device); + Boolean getDeviceStatus(Device device); /** * 根据IP和端口获取设备信息 @@ -161,4 +161,40 @@ public interface IDeviceService { Device getDeviceByChannelId(Integer channelId); Device getDeviceBySourceChannelDeviceId(String requesterId); + + void subscribeCatalog(int id, int cycle); + + void subscribeMobilePosition(int id, int cycle, int interval); + + WVPResult devicesSync(Device device); + + void deviceBasicConfig(Device device, BasicParam basicParam, ErrorCallback callback); + + void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback callback); + + void teleboot(Device device); + + void record(Device device, String channelId, String recordCmdStr, ErrorCallback callback); + + void guard(Device device, String guardCmdStr, ErrorCallback callback); + + void resetAlarm(Device device, String channelId, String alarmMethod, String alarmType, ErrorCallback callback); + + void iFrame(Device device, String channelId); + + void homePosition(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback callback); + + void dragZoomIn(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback callback); + + void dragZoomOut(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback callback); + + void deviceStatus(Device device, ErrorCallback callback); + + void updateDeviceHeartInfo(Device device); + + void alarm(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime, ErrorCallback callback); + + void deviceInfo(Device device, ErrorCallback callback); + + void queryPreset(Device device, String channelId, ErrorCallback callback); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelControlService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelControlService.java new file mode 100644 index 000000000..c552c5b45 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelControlService.java @@ -0,0 +1,16 @@ +package com.genersoft.iot.vmp.gb28181.service; + +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; + +public interface IGbChannelControlService { + + + void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); + void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); + void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); + void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); + void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); + void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback); +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java index 4f5779396..1d6e1ebe8 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelPlayService.java @@ -1,20 +1,33 @@ package com.genersoft.iot.vmp.gb28181.service; +import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; -import com.genersoft.iot.vmp.gb28181.bean.InviteInfo; +import com.genersoft.iot.vmp.gb28181.bean.InviteMessageInfo; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.service.bean.ErrorCallback; public interface IGbChannelPlayService { - void start(CommonGBChannel channel, InviteInfo inviteInfo, Platform platform, ErrorCallback callback); + void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback callback); - void play(CommonGBChannel channel, Platform platform, ErrorCallback callback); + void stopPlay(InviteSessionType type, CommonGBChannel channel, String stream); - void playGbDeviceChannel(CommonGBChannel channel, ErrorCallback callback); + void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback callback); - void playProxy(CommonGBChannel channel, ErrorCallback callback); + void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback callback); + + void stopPlayDeviceChannel(InviteSessionType type, CommonGBChannel channel, String stream); + + void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback callback); + + void stopPlayProxy(CommonGBChannel channel); void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback callback); + + void stopPlayPush(CommonGBChannel channel); + + void pauseRtp(String streamId); + + void resumeRtp(String streamId); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java index 8dc67df20..82c9b4066 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IGbChannelService.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.service; import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.github.pagehelper.PageInfo; @@ -87,4 +88,13 @@ public interface IGbChannelService { PageInfo queryList(int page, int count, String query, Boolean online, Boolean hasRecordPlan, Integer channelType); + void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback callback); + + PageInfo queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType); + + void clearChannelCivilCode(Boolean all, List channelIds); + + PageInfo queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType); + + void clearChannelParent(Boolean all, List channelIds); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPTZService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPTZService.java index d7c468052..c825c1cce 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPTZService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPTZService.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.gb28181.service; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Preset; @@ -18,4 +19,6 @@ public interface IPTZService { void ptz(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed); void frontEndCommand(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combindCode2); + + void frontEndCommand(CommonGBChannel channel, Integer cmdCode, Integer parameter1, Integer parameter2, Integer combindCode2); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java index e03e0907e..0d97aa297 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformChannelService.java @@ -43,6 +43,8 @@ public interface IPlatformChannelService { CommonGBChannel queryChannelByPlatformIdAndChannelId(Integer platformId, Integer channelId); + List queryChannelByPlatformIdAndChannelIds(Integer platformId, List channelIds); + void checkRegionAdd(List channelList); void checkRegionRemove(List channelList, List regionList); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java index 7858269cf..a6c2b2466 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlatformService.java @@ -76,13 +76,13 @@ public interface IPlatformService { /** * 语音喊话回复BYE */ - void stopBroadcast(Platform platform, CommonGBChannel channel, String stream, boolean sendBye, MediaServer mediaServerItem); + void stopBroadcast(Platform platform, CommonGBChannel channel, String app, String stream, boolean sendBye, MediaServer mediaServerItem); void addSimulatedSubscribeInfo(Platform parentPlatform); Platform queryOne(Integer platformId); - List queryEnablePlatformList(); + List queryEnablePlatformList(String serverId); void delete(Integer platformId, CommonCallback callback); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlayService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlayService.java index aa2ca3ab6..50c49776a 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IPlayService.java @@ -25,6 +25,8 @@ public interface IPlayService { SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback callback); + void play(Device device, DeviceChannel channel, ErrorCallback callback); + StreamInfo onPublishHandlerForPlay(MediaServer mediaServerItem, MediaInfo mediaInfo, Device device, DeviceChannel channel); MediaServer getNewMediaServerItem(Device device); @@ -38,7 +40,7 @@ public interface IPlayService { void zlmServerOnline(MediaServer mediaServer); - AudioBroadcastResult audioBroadcast(Device device, DeviceChannel deviceChannel, Boolean broadcastMode); + AudioBroadcastResult audioBroadcast(String deviceId, String channelDeviceId, Boolean broadcastMode); boolean audioBroadcastCmd(Device device, DeviceChannel channel, MediaServer mediaServerItem, String app, String stream, int timeout, boolean isFromPlatform, AudioBroadcastEvent event) throws InvalidArgumentException, ParseException, SipException; @@ -64,10 +66,14 @@ public interface IPlayService { void stop(InviteInfo inviteInfo); - void play(CommonGBChannel channel, ErrorCallback callback); + void play(CommonGBChannel channel, Boolean record, ErrorCallback callback); + + void stop(InviteSessionType inviteSessionType, CommonGBChannel channel, String stream); void playBack(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback callback); void download(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed, ErrorCallback callback); + + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java index 0bd8700db..6a2b9296c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/IRegionService.java @@ -36,4 +36,8 @@ public interface IRegionService { boolean batchAdd(List regionList); List getPath(String deviceId); + + String getDescription(String civilCode); + + void addByCivilCode(String civilCode); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceAlarmServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceAlarmServiceImpl.java index a08111af1..9dd6e6410 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceAlarmServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceAlarmServiceImpl.java @@ -1,9 +1,8 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm; -import com.genersoft.iot.vmp.gb28181.service.IDeviceAlarmService; import com.genersoft.iot.vmp.gb28181.dao.DeviceAlarmMapper; +import com.genersoft.iot.vmp.gb28181.service.IDeviceAlarmService; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; @@ -12,7 +11,6 @@ import org.springframework.stereotype.Service; import java.util.List; @Service -@DS("master") public class DeviceAlarmServiceImpl implements IDeviceAlarmService { @Autowired diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java index 4f4e9a1ba..61162fa60 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceChannelServiceImpl.java @@ -1,26 +1,29 @@ package com.genersoft.iot.vmp.gb28181.service.impl; import com.alibaba.fastjson2.JSONObject; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; +import com.genersoft.iot.vmp.common.enums.DeviceControlType; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; -import com.genersoft.iot.vmp.gb28181.bean.GbCode; -import com.genersoft.iot.vmp.gb28181.bean.MobilePosition; +import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.controller.bean.ChannelReduce; import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper; import com.genersoft.iot.vmp.gb28181.dao.DeviceMobilePositionMapper; import com.genersoft.iot.vmp.gb28181.dao.PlatformChannelMapper; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.event.record.RecordInfoEndEvent; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; +import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; @@ -29,21 +32,35 @@ import com.genersoft.iot.vmp.web.gb28181.dto.DeviceChannelExtend; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; +import org.dom4j.Element; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import java.text.ParseException; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; +import javax.sip.message.Response; +import javax.validation.constraints.NotNull; +import java.text.ParseException; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.SynchronousQueue; +import java.util.concurrent.TimeUnit; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; /** * @author lin */ @Slf4j @Service -@DS("master") public class DeviceChannelServiceImpl implements IDeviceChannelService { @Autowired @@ -73,6 +90,30 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @Autowired private IPlatformChannelService platformChannelService; + @Autowired + private IRedisRpcPlayService redisRpcPlayService; + + @Autowired + private ISIPCommander commander; + + // 记录录像查询的结果等待 + private final Map> topicSubscribers = new ConcurrentHashMap<>(); + + /** + * 监听录像查询结束事件 + */ + @Async("taskExecutor") + @org.springframework.context.event.EventListener + public void onApplicationEvent(RecordInfoEndEvent event) { + SynchronousQueue queue = topicSubscribers.get("record" + event.getRecordInfo().getSn()); + if (queue != null) { + queue.offer(event.getRecordInfo()); + } + } + + @Autowired + private ISIPCommander cmder; + @Override public int updateChannels(Device device, List channels) { @@ -84,7 +125,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { List channelList = channelMapper.queryChannelsByDeviceDbId(device.getId()); if (channelList.isEmpty()) { for (DeviceChannel channel : channels) { - channel.setDeviceDbId(device.getId()); + channel.setDataDeviceId(device.getId()); InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); if (inviteInfo != null && inviteInfo.getStreamInfo() != null) { channel.setStreamId(inviteInfo.getStreamInfo().getStream()); @@ -96,7 +137,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { } }else { for (DeviceChannel deviceChannel : channelList) { - channelsInStore.put(deviceChannel.getDeviceDbId() + deviceChannel.getDeviceId(), deviceChannel); + channelsInStore.put(deviceChannel.getDataDeviceId() + deviceChannel.getDeviceId(), deviceChannel); } for (DeviceChannel channel : channels) { InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); @@ -105,7 +146,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { } String now = DateUtil.getNow(); channel.setUpdateTime(now); - DeviceChannel deviceChannelInDb = channelsInStore.get(channel.getDeviceDbId() + channel.getDeviceId()); + DeviceChannel deviceChannelInDb = channelsInStore.get(channel.getDataDeviceId() + channel.getDeviceId()); if ( deviceChannelInDb != null) { channel.setId(deviceChannelInDb.getId()); channel.setUpdateTime(now); @@ -166,10 +207,8 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @Override public ResourceBaseInfo getOverview() { - int online = channelMapper.getOnlineCount(); int total = channelMapper.getAllChannelCount(); - return new ResourceBaseInfo(total, online); } @@ -324,7 +363,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { } for (DeviceChannel channel : channels) { if (channel.getParentId() != null) { - channelMapper.updateChannelSubCount(channel.getDeviceDbId(), channel.getParentId()); + channelMapper.updateChannelSubCount(channel.getDataDeviceId(), channel.getParentId()); } } } @@ -364,6 +403,39 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { return channelMapper.queryChaneIdListByDeviceDbIds(deviceDbIds); } + @Override + public void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback callback) { + + // 根据通道ID,获取所属设备 + Device device = deviceMapper.query(dataDeviceId); + if (device == null) { + // 不存在则回复404 + log.warn("[INFO 消息] 通道所属设备不存在, 设备ID: {}", dataDeviceId); + callback.run(Response.NOT_FOUND, "device not found", null); + return; + } + + DeviceChannel deviceChannel = channelMapper.getOneForSource(gbId); + if (deviceChannel == null) { + log.warn("[deviceControl] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(), + device.getDeviceId(), gbId); + callback.run(Response.NOT_FOUND, "channel not found", null); + return; + } + log.info("[deviceControl] 命令: {}, 设备: {}({}), 通道{}({}", type, device.getName(), device.getDeviceId(), + deviceChannel.getName(), deviceChannel.getDeviceId()); + String cmdString = getText(rootElement, type.getVal()); + try { + cmder.fronEndCmd(device, deviceChannel.getDeviceId(), cmdString, errorResult->{ + callback.run(errorResult.statusCode, errorResult.msg, null); + }, errorResult->{ + callback.run(errorResult.statusCode, errorResult.msg, null); + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 云台/前端: {}", e.getMessage()); + } + } + @Override public void updateChannelGPS(Device device, DeviceChannel deviceChannel, MobilePosition mobilePosition) { if (userSetting.getSavePositionHistory()) { @@ -487,7 +559,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { Map allChannelMap = new HashMap<>(); if (!allChannels.isEmpty()) { for (DeviceChannel deviceChannel : allChannels) { - allChannelMap.put(deviceChannel.getDeviceDbId() + deviceChannel.getDeviceId(), deviceChannel); + allChannelMap.put(deviceChannel.getDataDeviceId() + deviceChannel.getDeviceId(), deviceChannel); } } // 数据去重 @@ -500,16 +572,16 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { Map subContMap = new HashMap<>(); for (DeviceChannel deviceChannel : deviceChannelList) { - DeviceChannel channelInDb = allChannelMap.get(deviceChannel.getDeviceDbId() + deviceChannel.getDeviceId()); + DeviceChannel channelInDb = allChannelMap.get(deviceChannel.getDataDeviceId() + deviceChannel.getDeviceId()); if (channelInDb != null) { deviceChannel.setStreamId(channelInDb.getStreamId()); deviceChannel.setHasAudio(channelInDb.isHasAudio()); deviceChannel.setId(channelInDb.getId()); if (channelInDb.getStatus() != null && channelInDb.getStatus().equalsIgnoreCase(deviceChannel.getStatus())){ - List ids = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getDeviceId()); - if (!CollectionUtils.isEmpty(ids)){ - ids.forEach(platformId->{ - eventPublisher.catalogEventPublish(platformId, deviceChannel, deviceChannel.getStatus().equals("ON")? CatalogEvent.ON:CatalogEvent.OFF); + List platformList = platformChannelMapper.queryParentPlatformByChannelId(deviceChannel.getDeviceId()); + if (!CollectionUtils.isEmpty(platformList)){ + platformList.forEach(platform->{ + eventPublisher.catalogEventPublish(platform, deviceChannel.buildCommonGBChannelForStatus(), deviceChannel.getStatus().equals("ON")? CatalogEvent.ON:CatalogEvent.OFF); }); } } @@ -520,7 +592,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { deviceChannel.setUpdateTime(DateUtil.getNow()); addChannels.add(deviceChannel); } - allChannelMap.remove(deviceDbId + deviceChannel.getDeviceId()); + allChannelMap.remove(deviceChannel.getDataDeviceId() + deviceChannel.getDeviceId()); channels.add(deviceChannel); if (!ObjectUtils.isEmpty(deviceChannel.getParentId())) { if (subContMap.get(deviceChannel.getParentId()) == null) { @@ -700,6 +772,8 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { @Override public void addChannel(DeviceChannel channel) { + channel.setDataType(ChannelDataType.GB28181.value); + channel.setDataDeviceId(channel.getDataDeviceId()); channelMapper.add(channel); } @@ -707,4 +781,57 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService { public void updateChannelForNotify(DeviceChannel channel) { channelMapper.updateChannelForNotify(channel); } + + @Override + public void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())){ + redisRpcPlayService.queryRecordInfo(device.getServerId(), channel.getId(), startTime, endTime, callback); + return; + } + try { + int sn = (int)((Math.random()*9+1)*100000); + commander.recordInfoQuery(device, channel.getDeviceId(), startTime, endTime, sn, null, null, eventResult -> { + try { + // 消息发送成功, 监听等待数据到来 + SynchronousQueue queue = new SynchronousQueue<>(); + topicSubscribers.put("record" + sn, queue); + RecordInfo recordInfo = queue.poll(userSetting.getRecordInfoTimeout(), TimeUnit.MILLISECONDS); + if (recordInfo != null) { + callback.run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), recordInfo); + }else { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), recordInfo); + } + } catch (InterruptedException e) { + callback.run(ErrorCode.ERROR100.getCode(), e.getMessage(), null); + } finally { + this.topicSubscribers.remove("record" + sn); + } + + }, (eventResult -> { + callback.run(ErrorCode.ERROR100.getCode(), "查询录像失败, status: " + eventResult.statusCode + ", message: " + eventResult.msg, null); + })); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 查询录像: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback callback) { + if (channel.getDataType() != ChannelDataType.GB28181.value){ + // 只支持国标的语音喊话 + log.warn("[INFO 消息] 非国标设备, 通道ID: {}", channel.getGbId()); + callback.run(ErrorCode.ERROR100.getCode(), "非国标设备", null); + return; + } + Device device = deviceMapper.query(channel.getDataDeviceId()); + if (device == null) { + log.warn("[点播] 未找到通道{}的设备信息", channel); + callback.run(ErrorCode.ERROR100.getCode(), "设备不存在", null); + return; + } + DeviceChannel deviceChannel = getOneForSourceById(channel.getGbId()); + queryRecordInfo(device, deviceChannel, startTime, endTime, callback); + + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java index c5be6386b..c36d94800 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/DeviceServiceImpl.java @@ -1,9 +1,9 @@ package com.genersoft.iot.vmp.gb28181.service.impl; import com.alibaba.fastjson2.JSON; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.VideoManagerConstants; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; @@ -11,7 +11,6 @@ import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.dao.DeviceChannelMapper; import com.genersoft.iot.vmp.gb28181.dao.DeviceMapper; import com.genersoft.iot.vmp.gb28181.dao.PlatformChannelMapper; -import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IInviteStreamService; import com.genersoft.iot.vmp.gb28181.session.AudioBroadcastManager; @@ -24,22 +23,29 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respons import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import com.genersoft.iot.vmp.vmanager.bean.ResourceBaseInfo; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; import javax.sip.InvalidArgumentException; import javax.sip.SipException; +import javax.validation.constraints.NotNull; import java.text.ParseException; import java.time.Instant; import java.util.List; +import java.util.Objects; +import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; /** @@ -47,7 +53,6 @@ import java.util.concurrent.TimeUnit; */ @Slf4j @Service -@DS("master") public class DeviceServiceImpl implements IDeviceService { @Autowired @@ -71,9 +76,6 @@ public class DeviceServiceImpl implements IDeviceService { @Autowired private PlatformChannelMapper platformChannelMapper; - @Autowired - private IDeviceChannelService deviceChannelService; - @Autowired private DeviceChannelMapper deviceChannelMapper; @@ -95,11 +97,18 @@ public class DeviceServiceImpl implements IDeviceService { @Autowired private AudioBroadcastManager audioBroadcastManager; + @Autowired + private IRedisRpcService redisRpcService; + + private Device getDeviceByDeviceIdFromDb(String deviceId) { + return deviceMapper.getDeviceByDeviceId(deviceId); + } + @Override public void online(Device device, SipTransactionInfo sipTransactionInfo) { log.info("[设备上线] deviceId:{}->{}:{}", device.getDeviceId(), device.getIp(), device.getPort()); Device deviceInRedis = redisCatchStorage.getDevice(device.getDeviceId()); - Device deviceInDb = deviceMapper.getDeviceByDeviceId(device.getDeviceId()); + Device deviceInDb = getDeviceByDeviceIdFromDb(device.getDeviceId()); String now = DateUtil.getNow(); if (deviceInRedis != null && deviceInDb == null) { @@ -108,9 +117,12 @@ public class DeviceServiceImpl implements IDeviceService { } device.setUpdateTime(now); device.setKeepaliveTime(now); - if (device.getKeepaliveIntervalTime() == 0) { - // 默认心跳间隔60 - device.setKeepaliveIntervalTime(60); + if (device.getHeartBeatCount() == null) { + // 读取设备配置, 获取心跳间隔和心跳超时次数, 在次之前暂时设置为默认值 + device.setHeartBeatCount(3); + device.setHeartBeatInterval(60); + device.setPositionCapability(0); + } if (sipTransactionInfo != null) { device.setSipTransactionInfo(sipTransactionInfo); @@ -129,7 +141,8 @@ public class DeviceServiceImpl implements IDeviceService { deviceMapper.add(device); redisCatchStorage.updateDevice(device); try { - commander.deviceInfoQuery(device); + commander.deviceInfoQuery(device, null); + commander.deviceConfigQuery(device, null, "BasicParam", null); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 查询设备信息: {}", e.getMessage()); } @@ -143,7 +156,7 @@ public class DeviceServiceImpl implements IDeviceService { if (userSetting.getSyncChannelOnDeviceOnline()) { log.info("[设备上线,离线状态下重新注册]: {},查询设备信息以及通道信息", device.getDeviceId()); try { - commander.deviceInfoQuery(device); + commander.deviceInfoQuery(device, null); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 查询设备信息: {}", e.getMessage()); } @@ -176,28 +189,28 @@ public class DeviceServiceImpl implements IDeviceService { // 刷新过期任务 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 - dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "首次注册后未能收到心跳"), device.getKeepaliveIntervalTime() * 1000 * 3); - -// -// try { -// cmder.alarmSubscribe(device, 600, "0", "4", "0", "2023-7-27T00:00:00", "2023-7-28T00:00:00"); -// } catch (InvalidArgumentException e) { -// throw new RuntimeException(e); -// } catch (SipException e) { -// throw new RuntimeException(e); -// } catch (ParseException e) { -// throw new RuntimeException(e); -// } + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); } @Override public void offline(String deviceId, String reason) { - log.warn("[设备离线],{}, device:{}", reason, deviceId); - Device device = deviceMapper.getDeviceByDeviceId(deviceId); + Device device = getDeviceByDeviceIdFromDb(deviceId); if (device == null) { + log.warn("[设备不存在] device:{}", deviceId); return; } + + // 主动查询设备状态 + Boolean deviceStatus = getDeviceStatus(device); + if (deviceStatus != null && deviceStatus) { + log.info("[设备离线] 主动探测发现设备在线,暂不处理 device:{}", deviceId); + online(device, null); + return; + } + log.info("[设备离线] {}, device:{}, 心跳间隔: {},心跳超时次数: {}, 上次心跳时间:{}, 上次注册时间: {}", reason, deviceId, + device.getHeartBeatInterval(), device.getHeartBeatCount(), device.getKeepaliveTime(), device.getRegisterTime()); String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + deviceId; dynamicTask.stop(registerExpireTaskKey); if (device.isOnLine()) { @@ -214,7 +227,7 @@ public class DeviceServiceImpl implements IDeviceService { // deviceChannelMapper.offlineByDeviceId(deviceId); // 离线释放所有ssrc List ssrcTransactions = sessionManager.getSsrcTransactionByDeviceId(deviceId); - if (ssrcTransactions != null && ssrcTransactions.size() > 0) { + if (ssrcTransactions != null && !ssrcTransactions.isEmpty()) { for (SsrcTransaction ssrcTransaction : ssrcTransactions) { mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); @@ -261,6 +274,9 @@ public class DeviceServiceImpl implements IDeviceService { @Override public boolean removeCatalogSubscribe(Device device, CommonCallback callback) { if (device == null || device.getSubscribeCycleForCatalog() < 0) { + if (callback != null) { + callback.run(false); + } return false; } log.info("[移除目录订阅]: {}", device.getDeviceId()); @@ -270,6 +286,16 @@ public class DeviceServiceImpl implements IDeviceService { if (runnable instanceof ISubscribeTask) { ISubscribeTask subscribeTask = (ISubscribeTask) runnable; subscribeTask.stop(callback); + }else { + log.info("[移除目录订阅]失败,未找到订阅任务 : {}", device.getDeviceId()); + if (callback != null) { + callback.run(false); + } + } + }else { + log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId()); + if (callback != null) { + callback.run(false); } } dynamicTask.stop(taskKey); @@ -295,6 +321,9 @@ public class DeviceServiceImpl implements IDeviceService { @Override public boolean removeMobilePositionSubscribe(Device device, CommonCallback callback) { if (device == null || device.getSubscribeCycleForCatalog() < 0) { + if (callback != null) { + callback.run(false); + } return false; } log.info("[移除移动位置订阅]: {}", device.getDeviceId()); @@ -304,6 +333,16 @@ public class DeviceServiceImpl implements IDeviceService { if (runnable instanceof ISubscribeTask) { ISubscribeTask subscribeTask = (ISubscribeTask) runnable; subscribeTask.stop(callback); + }else { + log.info("[移除移动位置订阅]失败,未找到订阅任务 : {}", device.getDeviceId()); + if (callback != null) { + callback.run(false); + } + } + }else { + log.info("[移除移动位置订阅]失败,设备已经离线 : {}", device.getDeviceId()); + if (callback != null) { + callback.run(false); } } dynamicTask.stop(taskKey); @@ -312,6 +351,13 @@ public class DeviceServiceImpl implements IDeviceService { @Override public SyncStatus getChannelSyncStatus(String deviceId) { + Device device = deviceMapper.getDeviceByDeviceId(deviceId); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR404.getCode(), "设备不存在"); + } + if (!userSetting.getServerId().equals(device.getServerId())) { + return redisRpcService.getChannelSyncStatus(device.getServerId(), deviceId); + } return catalogResponseMessageHandler.getChannelSyncProgress(deviceId); } @@ -346,7 +392,7 @@ public class DeviceServiceImpl implements IDeviceService { public Device getDeviceByDeviceId(String deviceId) { Device device = redisCatchStorage.getDevice(deviceId); if (device == null) { - device = deviceMapper.getDeviceByDeviceId(deviceId); + device = getDeviceByDeviceIdFromDb(deviceId); if (device != null) { redisCatchStorage.updateDevice(device); } @@ -355,13 +401,13 @@ public class DeviceServiceImpl implements IDeviceService { } @Override - public List getAllOnlineDevice() { - return deviceMapper.getOnlineDevices(); + public List getAllOnlineDevice(String serverId) { + return deviceMapper.getOnlineDevicesByServerId(serverId); } @Override public List getAllByStatus(Boolean status) { - return deviceMapper.getDevices(status); + return deviceMapper.getDevices(ChannelDataType.GB28181.value, status); } @Override @@ -372,16 +418,23 @@ public class DeviceServiceImpl implements IDeviceService { } @Override - public void checkDeviceStatus(Device device) { - if (device == null || !device.isOnLine()) { - return; - } + public Boolean getDeviceStatus(@NotNull Device device) { + SynchronousQueue queue = new SynchronousQueue<>(); try { - sipCommander.deviceStatusQuery(device, null); - } catch (InvalidArgumentException | SipException | ParseException e) { + sipCommander.deviceStatusQuery(device, ((code, msg, data) -> { + queue.offer(msg); + })); + String data = queue.poll(10, TimeUnit.SECONDS); + if (data != null && "ONLINE".equalsIgnoreCase(data.trim())) { + return Boolean.TRUE; + }else { + return Boolean.FALSE; + } + + } catch (InvalidArgumentException | SipException | ParseException | InterruptedException e) { log.error("[命令发送失败] 设备状态查询: {}", e.getMessage()); } - + return null; } @Override @@ -403,7 +456,7 @@ public class DeviceServiceImpl implements IDeviceService { @Override public boolean isExist(String deviceId) { - return deviceMapper.getDeviceByDeviceId(deviceId) != null; + return getDeviceByDeviceIdFromDb(deviceId) != null; } @Override @@ -412,71 +465,19 @@ public class DeviceServiceImpl implements IDeviceService { device.setCreateTime(DateUtil.getNow()); device.setUpdateTime(DateUtil.getNow()); if(device.getStreamMode() == null) { - device.setStreamMode("UDP"); + device.setStreamMode("TCP-PASSIVE"); } deviceMapper.addCustomDevice(device); } @Override public void updateCustomDevice(Device device) { + // 订阅状态的修改使用一个单独方法控制,此处不再进行状态修改 Device deviceInStore = deviceMapper.query(device.getId()); if (deviceInStore == null) { log.warn("更新设备时未找到设备信息"); return; } - // 目录订阅相关的信息 - if (deviceInStore.getSubscribeCycleForCatalog() != device.getSubscribeCycleForCatalog()) { - if (device.getSubscribeCycleForCatalog() > 0) { - // 若已开启订阅,但订阅周期不同,则先取消 - if (deviceInStore.getSubscribeCycleForCatalog() != 0) { - removeCatalogSubscribe(deviceInStore, result->{ - // 开启订阅 - deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); - addCatalogSubscribe(deviceInStore); - // 因为是异步执行,需要在这里更新下数据 - deviceMapper.updateCustom(deviceInStore); - redisCatchStorage.updateDevice(deviceInStore); - }); - }else { - // 开启订阅 - deviceInStore.setSubscribeCycleForCatalog(device.getSubscribeCycleForCatalog()); - addCatalogSubscribe(deviceInStore); - } - - }else if (device.getSubscribeCycleForCatalog() == 0) { - // 取消订阅 - deviceInStore.setSubscribeCycleForCatalog(0); - removeCatalogSubscribe(deviceInStore, null); - } - } - // 移动位置订阅相关的信息 - if (deviceInStore.getSubscribeCycleForMobilePosition() != device.getSubscribeCycleForMobilePosition()) { - if (device.getSubscribeCycleForMobilePosition() > 0) { - // 若已开启订阅,但订阅周期不同,则先取消 - if (deviceInStore.getSubscribeCycleForMobilePosition() != 0) { - removeMobilePositionSubscribe(deviceInStore, result->{ - // 开启订阅 - deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); - deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval()); - addMobilePositionSubscribe(deviceInStore); - // 因为是异步执行,需要在这里更新下数据 - deviceMapper.updateCustom(deviceInStore); - redisCatchStorage.updateDevice(deviceInStore); - }); - }else { - // 开启订阅 - deviceInStore.setSubscribeCycleForMobilePosition(device.getSubscribeCycleForMobilePosition()); - deviceInStore.setMobilePositionSubmissionInterval(device.getMobilePositionSubmissionInterval()); - addMobilePositionSubscribe(deviceInStore); - } - - }else if (device.getSubscribeCycleForMobilePosition() == 0) { - // 取消订阅 - deviceInStore.setSubscribeCycleForMobilePosition(0); - deviceInStore.setMobilePositionSubmissionInterval(0); - removeMobilePositionSubscribe(deviceInStore, null); - } - } if (deviceInStore.getGeoCoordSys() != null) { // 坐标系变化,需要重新计算GCJ02坐标和WGS84坐标 if (!deviceInStore.getGeoCoordSys().equals(device.getGeoCoordSys())) { @@ -496,10 +497,8 @@ public class DeviceServiceImpl implements IDeviceService { @Override @Transactional public boolean delete(String deviceId) { - Device device = deviceMapper.getDeviceByDeviceId(deviceId); - if (device == null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到设备:" + deviceId); - } + Device device = getDeviceByDeviceIdFromDb(deviceId); + Assert.notNull(device, "未找到设备"); platformChannelMapper.delChannelForDeviceId(deviceId); deviceChannelMapper.cleanChannelsByDeviceId(device.getId()); deviceMapper.del(deviceId); @@ -527,7 +526,7 @@ public class DeviceServiceImpl implements IDeviceService { .replaceAll("%", "/%") .replaceAll("_", "/_"); } - List all = deviceMapper.getDeviceList(query, status); + List all = deviceMapper.getDeviceList(ChannelDataType.GB28181.value, query, status); return new PageInfo<>(all); } @@ -538,11 +537,403 @@ public class DeviceServiceImpl implements IDeviceService { @Override public Device getDeviceByChannelId(Integer channelId) { - return deviceMapper.queryByChannelId(channelId); + return deviceMapper.queryByChannelId(ChannelDataType.GB28181.value,channelId); } @Override public Device getDeviceBySourceChannelDeviceId(String channelId) { - return deviceMapper.getDeviceBySourceChannelDeviceId(channelId); + return deviceMapper.getDeviceBySourceChannelDeviceId(ChannelDataType.GB28181.value,channelId); + } + + @Override + public void subscribeCatalog(int id, int cycle) { + Device device = deviceMapper.query(id); + Assert.notNull(device, "未找到设备"); + + if (device.getSubscribeCycleForCatalog() == cycle) { + return; + } + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.subscribeCatalog(id, cycle); + return; + } + // 目录订阅相关的信息 + if (device.getSubscribeCycleForCatalog() > 0) { + // 订阅周期不同,则先取消 + removeCatalogSubscribe(device, result->{ + device.setSubscribeCycleForCatalog(cycle); + if (cycle > 0) { + // 开启订阅 + addCatalogSubscribe(device); + } + // 因为是异步执行,需要在这里更新下数据 + deviceMapper.updateSubscribeCatalog(device); + redisCatchStorage.updateDevice(device); + }); + }else { + // 开启订阅 + device.setSubscribeCycleForCatalog(cycle); + addCatalogSubscribe(device); + deviceMapper.updateSubscribeCatalog(device); + redisCatchStorage.updateDevice(device); + } + } + + @Override + public void subscribeMobilePosition(int id, int cycle, int interval) { + Device device = deviceMapper.query(id); + Assert.notNull(device, "未找到设备"); + if (device.getSubscribeCycleForMobilePosition() == cycle) { + return; + } + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.subscribeMobilePosition(id, cycle, interval); + return; + } + // 目录订阅相关的信息 + if (device.getSubscribeCycleForMobilePosition() > 0) { + // 订阅周期已经开启,则先取消 + removeMobilePositionSubscribe(device, result->{ + // 开启订阅 + device.setSubscribeCycleForMobilePosition(cycle); + device.setMobilePositionSubmissionInterval(interval); + if (cycle > 0) { + addMobilePositionSubscribe(device); + } + // 因为是异步执行,需要在这里更新下数据 + deviceMapper.updateSubscribeMobilePosition(device); + redisCatchStorage.updateDevice(device); + }); + }else { + // 订阅未开启 + device.setSubscribeCycleForMobilePosition(cycle); + device.setMobilePositionSubmissionInterval(interval); + // 开启订阅 + addMobilePositionSubscribe(device); + // 因为是异步执行,需要在这里更新下数据 + deviceMapper.updateSubscribeMobilePosition(device); + redisCatchStorage.updateDevice(device); + } + } + + @Override + public void updateDeviceHeartInfo(Device device) { + Device deviceInDb = deviceMapper.query(device.getId()); + if (deviceInDb == null) { + return; + } + if (!Objects.equals(deviceInDb.getHeartBeatCount(), device.getHeartBeatCount()) + || !Objects.equals(deviceInDb.getHeartBeatInterval(), device.getHeartBeatInterval())) { + // 刷新过期任务 + String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); + // 如果第一次注册那么必须在60 * 3时间内收到一个心跳,否则设备离线 + dynamicTask.startDelay(registerExpireTaskKey, ()-> offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); + deviceInDb.setHeartBeatCount(device.getHeartBeatCount()); + deviceInDb.setHeartBeatInterval(device.getHeartBeatInterval()); + deviceInDb.setPositionCapability(device.getPositionCapability()); + updateDevice(deviceInDb); + } + } + + @Override + public WVPResult devicesSync(Device device) { + if (!userSetting.getServerId().equals(device.getServerId())) { + return redisRpcService.devicesSync(device.getServerId(), device.getDeviceId()); + } + // 已存在则返回进度 + if (isSyncRunning(device.getDeviceId())) { + SyncStatus channelSyncStatus = getChannelSyncStatus(device.getDeviceId()); + WVPResult wvpResult = new WVPResult(); + if (channelSyncStatus.getErrorMsg() != null) { + wvpResult.setCode(ErrorCode.ERROR100.getCode()); + wvpResult.setMsg(channelSyncStatus.getErrorMsg()); + }else if (channelSyncStatus.getTotal() == null || channelSyncStatus.getTotal() == 0){ + wvpResult.setCode(ErrorCode.SUCCESS.getCode()); + wvpResult.setMsg("等待通道信息..."); + }else { + wvpResult.setCode(ErrorCode.SUCCESS.getCode()); + wvpResult.setMsg(ErrorCode.SUCCESS.getMsg()); + wvpResult.setData(channelSyncStatus); + } + return wvpResult; + } + sync(device); + WVPResult wvpResult = new WVPResult<>(); + wvpResult.setCode(0); + wvpResult.setMsg("开始同步"); + return wvpResult; + } + + @Override + public void deviceBasicConfig(Device device, BasicParam basicParam, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.deviceBasicConfig(device.getServerId(), device, basicParam); + if (result.getCode() == ErrorCode.SUCCESS.getCode()) { + callback.run(result.getCode(), result.getMsg(), result.getData()); + } + return; + } + + try { + sipCommander.deviceBasicConfigCmd(device, basicParam, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 设备配置: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + } + + @Override + public void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback callback) { + + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.deviceConfigQuery(device.getServerId(), device, channelId, configType); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.deviceConfigQuery(device, channelId, configType, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 获取设备配置: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + } + + @Override + public void teleboot(Device device) { + + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.teleboot(device.getServerId(), device); + } + try { + sipCommander.teleBootCmd(device); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 远程启动: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void record(Device device, String channelId, String recordCmdStr, ErrorCallback callback) { + + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.recordControl(device.getServerId(), device, channelId, recordCmdStr); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.recordCmd(device, channelId, recordCmdStr, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 开始/停止录像: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + } + + @Override + public void guard(Device device, String guardCmdStr, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.guard(device.getServerId(), device, guardCmdStr); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.guardCmd(device, guardCmdStr, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + } + + @Override + public void resetAlarm(Device device, String channelId, String alarmMethod, String alarmType, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.resetAlarm(device.getServerId(), device, channelId, alarmMethod, alarmType); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + try { + sipCommander.alarmResetCmd(device, alarmMethod, alarmType, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 布防/撤防操作: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + + } + + @Override + public void iFrame(Device device, String channelId) { + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.iFrame(device.getServerId(), device, channelId); + return; + } + + try { + sipCommander.iFrameCmd(device, channelId); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 强制关键帧操作: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage()); + } + } + + @Override + public void homePosition(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.homePosition(device.getServerId(), device, channelId, enabled, resetTime, presetIndex); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.homePositionCmd(device, channelId, enabled, resetTime, presetIndex, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 看守位控制: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void dragZoomIn(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.dragZoomIn(device.getServerId(), device, channelId, length, width, midpointx, midpointy, lengthx, lengthy); + return; + } + + StringBuffer cmdXml = new StringBuffer(200); + cmdXml.append("\r\n"); + cmdXml.append("" + length+ "\r\n"); + cmdXml.append("" + width+ "\r\n"); + cmdXml.append("" + midpointx+ "\r\n"); + cmdXml.append("" + midpointy+ "\r\n"); + cmdXml.append("" + lengthx+ "\r\n"); + cmdXml.append("" + lengthy+ "\r\n"); + cmdXml.append("\r\n"); + try { + sipCommander.dragZoomCmd(device, channelId, cmdXml.toString(), callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 拉框放大: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void dragZoomOut(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcService.dragZoomOut(device.getServerId(), device, channelId, length, width, midpointx, midpointy, lengthx, lengthy); + return; + } + + StringBuffer cmdXml = new StringBuffer(200); + cmdXml.append("\r\n"); + cmdXml.append("" + length+ "\r\n"); + cmdXml.append("" + width+ "\r\n"); + cmdXml.append("" + midpointx+ "\r\n"); + cmdXml.append("" + midpointy+ "\r\n"); + cmdXml.append("" + lengthx+ "\r\n"); + cmdXml.append("" + lengthy+ "\r\n"); + cmdXml.append("\r\n"); + try { + sipCommander.dragZoomCmd(device, channelId, cmdXml.toString(), callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 拉框放大: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void deviceStatus(Device device, ErrorCallback callback) { + + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.deviceStatus(device.getServerId(), device); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + try { + sipCommander.deviceStatusQuery(device, (code, msg, data) -> { + if ("ONLINE".equalsIgnoreCase(data.trim())) { + online(device, null); + }else { + offline(device.getDeviceId(), "设备状态查询结果:" + data.trim()); + } + if (callback != null) { + callback.run(code, msg, data); + } + }); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 获取设备状态: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + + @Override + public void alarm(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.alarm(device.getServerId(), device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + String startAlarmTime = ""; + if (startTime != null) { + startAlarmTime = DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(startTime); + } + String endAlarmTime = ""; + if (startTime != null) { + endAlarmTime = DateUtil.yyyy_MM_dd_HH_mm_ssToISO8601(endTime); + } + + try { + sipCommander.alarmInfoQuery(device, startPriority, endPriority, alarmMethod, alarmType, startAlarmTime, endAlarmTime, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 获取设备状态: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void deviceInfo(Device device, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.deviceInfo(device.getServerId(), device); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.deviceInfoQuery(device, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 获取设备信息: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + @Override + public void queryPreset(Device device, String channelId, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + WVPResult result = redisRpcService.queryPreset(device.getServerId(), device, channelId); + callback.run(result.getCode(), result.getMsg(), result.getData()); + return; + } + + try { + sipCommander.presetQuery(device, channelId, callback); + } catch (InvalidArgumentException | SipException | ParseException e) { + log.error("[命令发送失败] 预制位查询: {}", e.getMessage()); + callback.run(ErrorCode.ERROR100.getCode(), "命令发送: " + e.getMessage(), null); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelControlServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelControlServiceImpl.java new file mode 100644 index 000000000..4751c2eff --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelControlServiceImpl.java @@ -0,0 +1,43 @@ +package com.genersoft.iot.vmp.gb28181.service.impl; + +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.FrontEndControlCodeForPTZ; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class GbChannelControlServiceImpl implements IGbChannelControlService { + + @Override + public void ptz(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + log.info("[通用通道] 云台控制, 通道: {}", channel.getGbId()); + } + + @Override + public void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + log.info("[通用通道] 预置位, 通道: {}", channel.getGbId()); + } + + @Override + public void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + log.info("[通用通道] FI指令, 通道: {}", channel.getGbId()); + } + + @Override + public void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + + } + + @Override + public void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + + } + + @Override + public void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback callback) { + + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java index e0a736c7b..2e5b8e234 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelPlayServiceImpl.java @@ -1,21 +1,27 @@ package com.genersoft.iot.vmp.gb28181.service.impl; +import com.genersoft.iot.vmp.common.InviteSessionType; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.exception.ServiceException; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; -import com.genersoft.iot.vmp.gb28181.bean.InviteInfo; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.PlayException; import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; import com.genersoft.iot.vmp.gb28181.service.IPlayService; import com.genersoft.iot.vmp.service.bean.ErrorCallback; -import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService; import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.sip.InvalidArgumentException; +import javax.sip.SipException; import javax.sip.message.Response; +import java.text.ParseException; @Slf4j @Service @@ -30,25 +36,28 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { @Autowired private IStreamPushPlayService streamPushPlayService; + @Autowired + private UserSetting userSetting; + @Override - public void start(CommonGBChannel channel, InviteInfo inviteInfo, Platform platform, ErrorCallback callback) { - if (channel == null || inviteInfo == null || callback == null) { + public void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback callback) { + if (channel == null || inviteInfo == null || callback == null || channel.getDataType() == null) { log.warn("[通用通道点播] 参数异常, channel: {}, inviteInfo: {}, callback: {}", channel != null, inviteInfo != null, callback != null); throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); } log.info("[点播通用通道] 类型:{}, 通道: {}({})", inviteInfo.getSessionName(), channel.getGbName(), channel.getGbDeviceId()); if ("Play".equalsIgnoreCase(inviteInfo.getSessionName())) { - play(channel, platform, callback); + play(channel, platform, userSetting.getRecordSip(), callback); }else if ("Playback".equals(inviteInfo.getSessionName())) { - if (channel.getGbDeviceDbId() != null) { + if (channel.getDataType() == ChannelDataType.GB28181.value) { // 国标通道 playbackGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), callback); - } else if (channel.getStreamProxyId() != null) { + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { // 拉流代理 log.warn("[回放通用通道] 不支持回放拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); throw new PlayException(Response.FORBIDDEN, "forbidden"); - } else if (channel.getStreamPushId() != null) { + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { // 推流 log.warn("[回放通用通道] 不支持回放推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); throw new PlayException(Response.FORBIDDEN, "forbidden"); @@ -58,7 +67,7 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); } }else if ("Download".equals(inviteInfo.getSessionName())) { - if (channel.getGbDeviceDbId() != null) { + if (channel.getDataType() == ChannelDataType.GB28181.value) { int downloadSpeed = 4; try { if (inviteInfo.getDownloadSpeed() != null){ @@ -68,11 +77,11 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { // 国标通道 downloadGbDeviceChannel(channel, inviteInfo.getStartTime(), inviteInfo.getStopTime(), downloadSpeed, callback); - } else if (channel.getStreamProxyId() != null) { + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { // 拉流代理 log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); throw new PlayException(Response.FORBIDDEN, "forbidden"); - } else if (channel.getStreamPushId() != null) { + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { // 推流 log.warn("[下载通用通道录像] 不支持下载推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); throw new PlayException(Response.FORBIDDEN, "forbidden"); @@ -89,14 +98,32 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } @Override - public void play(CommonGBChannel channel, Platform platform, ErrorCallback callback) { - if (channel.getGbDeviceDbId() != null) { + public void stopPlay(InviteSessionType type, CommonGBChannel channel, String stream) { + if (channel.getDataType() == ChannelDataType.GB28181.value) { // 国标通道 - playGbDeviceChannel(channel, callback); - } else if (channel.getStreamProxyId() != null) { + stopPlayDeviceChannel(type, channel, stream); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { // 拉流代理 - playProxy(channel, callback); - } else if (channel.getStreamPushId() != null) { + stopPlayProxy(channel); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { + // 推流 + stopPlayPush(channel); + } else { + // 通道数据异常 + log.error("[点播通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback callback) { + if (channel.getDataType() == ChannelDataType.GB28181.value) { + // 国标通道 + playGbDeviceChannel(channel, record, callback); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { + // 拉流代理 + playProxy(channel, record, callback); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { if (platform != null) { // 推流 playPush(channel, platform.getServerGBId(), platform.getName(), callback); @@ -112,10 +139,10 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } @Override - public void playGbDeviceChannel(CommonGBChannel channel, ErrorCallback callback){ + public void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback callback){ // 国标通道 try { - deviceChannelPlayService.play(channel, callback); + deviceChannelPlayService.play(channel, record, callback); } catch (PlayException e) { callback.run(e.getCode(), e.getMsg(), null); } catch (Exception e) { @@ -125,25 +152,40 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } @Override - public void playProxy(CommonGBChannel channel, ErrorCallback callback){ + public void stopPlayDeviceChannel(InviteSessionType type, CommonGBChannel channel, String stream) { + // 国标通道 + try { + deviceChannelPlayService.stop(type, channel, stream); + } catch (Exception e) { + log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e); + } + } + + @Override + public void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback callback){ // 拉流代理通道 try { - StreamInfo streamInfo = streamProxyPlayService.start(channel.getStreamProxyId()); - if (streamInfo == null) { - callback.run(Response.BUSY_HERE, "busy here", null); - }else { - callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); - } + streamProxyPlayService.start(channel.getDataDeviceId(), record, callback); }catch (Exception e) { callback.run(Response.BUSY_HERE, "busy here", null); } } + @Override + public void stopPlayProxy(CommonGBChannel channel) { + // 拉流代理通道 + try { + streamProxyPlayService.stop(channel.getDataDeviceId()); + }catch (Exception e) { + log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e); + } + } + @Override public void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback callback){ // 推流 try { - streamPushPlayService.start(channel.getStreamPushId(), callback, platformDeviceId, platformName); + streamPushPlayService.start(channel.getDataDeviceId(), callback, platformDeviceId, platformName); }catch (PlayException e) { callback.run(e.getCode(), e.getMsg(), null); }catch (Exception e) { @@ -152,6 +194,16 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } } + @Override + public void stopPlayPush(CommonGBChannel channel) { + // 推流 + try { + streamPushPlayService.stop(channel.getDataDeviceId()); + }catch (Exception e) { + log.error("[停止点播失败] {}({})", channel.getGbName(), channel.getGbDeviceId(), e); + } + } + private void playbackGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback callback){ try { deviceChannelPlayService.playBack(channel, startTime, stopTime, callback); @@ -162,6 +214,20 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { } } + @Override + public void pauseRtp(String streamId) { + try { + deviceChannelPlayService.pauseRtp(streamId); + } catch (ServiceException | InvalidArgumentException | ParseException | SipException ignore) {} + } + + @Override + public void resumeRtp(String streamId) { + try { + deviceChannelPlayService.resumeRtp(streamId); + } catch (ServiceException | InvalidArgumentException | ParseException | SipException ignore) {} + } + private void downloadGbDeviceChannel(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed, ErrorCallback callback){ try { @@ -172,4 +238,6 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService { callback.run(Response.BUSY_HERE, "busy here", null); } } + + } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java index 792fd88bd..aaceab224 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GbChannelServiceImpl.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.service.impl; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper; @@ -8,8 +9,10 @@ import com.genersoft.iot.vmp.gb28181.dao.PlatformChannelMapper; import com.genersoft.iot.vmp.gb28181.dao.RegionMapper; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; @@ -22,7 +25,11 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; -import java.util.*; +import javax.sip.message.Response; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; @Slf4j @Service @@ -46,6 +53,9 @@ public class GbChannelServiceImpl implements IGbChannelService { @Autowired private GroupMapper groupMapper; + @Autowired + private IDeviceChannelService deviceChannelService; + @Override public CommonGBChannel queryByDeviceId(String gbDeviceId) { return commonGBChannelMapper.queryByDeviceId(gbDeviceId); @@ -53,17 +63,12 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public int add(CommonGBChannel commonGBChannel) { - if (commonGBChannel.getStreamPushId() != null && commonGBChannel.getStreamPushId() > 0) { - CommonGBChannel commonGBChannelInDb = commonGBChannelMapper.queryByStreamPushId(commonGBChannel.getStreamPushId()); - if (commonGBChannelInDb != null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "此推流已经关联通道"); - } + if (commonGBChannel.getDataType() == null || commonGBChannel.getDataDeviceId() == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "缺少通道数据类型或通道数据关联设备ID"); } - if (commonGBChannel.getStreamProxyId() != null && commonGBChannel.getStreamProxyId() > 0) { - CommonGBChannel commonGBChannelInDb = commonGBChannelMapper.queryByStreamProxyId(commonGBChannel.getStreamProxyId()); - if (commonGBChannelInDb != null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "此代理已经关联通道"); - } + CommonGBChannel commonGBChannelInDb = commonGBChannelMapper.queryByDataId(commonGBChannel.getDataType(), commonGBChannel.getDataDeviceId()); + if (commonGBChannelInDb != null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "此推流已经关联通道"); } commonGBChannel.setCreateTime(DateUtil.getNow()); commonGBChannel.setUpdateTime(DateUtil.getNow()); @@ -113,7 +118,7 @@ public class GbChannelServiceImpl implements IGbChannelService { public int update(CommonGBChannel commonGBChannel) { log.info("[更新通道] 通道ID: {}, ", commonGBChannel.getGbId()); if (commonGBChannel.getGbId() <= 0) { - log.warn("[更新通道] 未找到数据库ID,更新失败, {}", commonGBChannel.getGbDeviceDbId()); + log.warn("[更新通道] 未找到数据库ID,更新失败, {}({})", commonGBChannel.getGbName(), commonGBChannel.getGbDeviceId()); return 0; } commonGBChannel.setUpdateTime(DateUtil.getNow()); @@ -132,10 +137,10 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public int offline(CommonGBChannel commonGBChannel) { if (commonGBChannel.getGbId() <= 0) { - log.warn("[通道离线] 未找到数据库ID,更新失败, {}", commonGBChannel.getGbDeviceDbId()); + log.warn("[通道离线] 未找到数据库ID,更新失败, {}({})", commonGBChannel.getGbName(), commonGBChannel.getGbDeviceId()); return 0; } - int result = commonGBChannelMapper.updateStatusById(commonGBChannel.getGbId(), 0); + int result = commonGBChannelMapper.updateStatusById(commonGBChannel.getGbId(), "OFF"); if (result > 0) { try { // 发送通知 @@ -186,10 +191,10 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public int online(CommonGBChannel commonGBChannel) { if (commonGBChannel.getGbId() <= 0) { - log.warn("[通道上线] 未找到数据库ID,更新失败, {}", commonGBChannel.getGbDeviceDbId()); + log.warn("[通道上线] 未找到数据库ID,更新失败, {}({})", commonGBChannel.getGbName(), commonGBChannel.getGbDeviceId()); return 0; } - int result = commonGBChannelMapper.updateStatusById(commonGBChannel.getGbId(), 1); + int result = commonGBChannelMapper.updateStatusById(commonGBChannel.getGbId(), "ON"); if (result > 0) { try { // 发送通知 @@ -371,12 +376,12 @@ public class GbChannelServiceImpl implements IGbChannelService { log.warn("[重置国标通道] 未找到对应Id的通道: id: {}", id); throw new ControllerException(ErrorCode.ERROR400); } - if (channel.getGbDeviceDbId() <= 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { log.warn("[重置国标通道] 非国标下级通道无法重置: id: {}", id); throw new ControllerException(ErrorCode.ERROR100.getCode(), "非国标下级通道无法重置"); } // 这个多加一个参数,为了防止将非国标的通道通过此方法清空内容,导致意外发生 - commonGBChannelMapper.reset(id, channel.getGbDeviceDbId(), DateUtil.getNow()); + commonGBChannelMapper.reset(id, ChannelDataType.GB28181.value, channel.getDataDeviceId(), DateUtil.getNow()); CommonGBChannel channelNew = getOne(id); // 发送通过更新通知 try { @@ -499,7 +504,7 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public void addChannelToRegionByGbDevice(String civilCode, List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds); if (channelList.isEmpty()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在"); } @@ -520,7 +525,7 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public void deleteChannelToRegionByGbDevice(List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds); if (channelList.isEmpty()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在"); } @@ -637,7 +642,7 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override @Transactional public void addChannelToGroupByGbDevice(String parentId, String businessGroup, List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds); if (channelList.isEmpty()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在"); } @@ -665,7 +670,7 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public void deleteChannelToGroupByGbDevice(List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIds(ChannelDataType.GB28181.value, deviceIds); if (channelList.isEmpty()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "所有通道Id不存在"); } @@ -707,12 +712,12 @@ public class GbChannelServiceImpl implements IGbChannelService { @Override public List queryListByStreamPushList(List streamPushList) { - return commonGBChannelMapper.queryListByStreamPushList(streamPushList); + return commonGBChannelMapper.queryListByStreamPushList(ChannelDataType.STREAM_PUSH.value, streamPushList); } @Override public void updateGpsByDeviceIdForStreamPush(List channels) { - commonGBChannelMapper.updateGpsByDeviceIdForStreamPush(channels); + commonGBChannelMapper.updateGpsByDeviceIdForStreamPush(ChannelDataType.STREAM_PUSH.value, channels); } @Override @@ -726,4 +731,70 @@ public class GbChannelServiceImpl implements IGbChannelService { List all = commonGBChannelMapper.queryList(query, online, hasRecordPlan, channelType); return new PageInfo<>(all); } + + @Override + public void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback callback) { + if (channel.getDataType() == ChannelDataType.GB28181.value) { + deviceChannelService.queryRecordInfo(channel, startTime, endTime, callback); + } else if (channel.getDataType() == ChannelDataType.STREAM_PROXY.value) { + // 拉流代理 + log.warn("[下载通用通道录像] 不支持下载拉流代理的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.FORBIDDEN, "forbidden"); + } else if (channel.getDataType() == ChannelDataType.STREAM_PUSH.value) { + // 推流 + log.warn("[下载通用通道录像] 不支持下载推流的录像: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.FORBIDDEN, "forbidden"); + } else { + // 通道数据异常 + log.error("[回放通用通道] 通道数据异常,无法识别通道来源: {}({})", channel.getGbName(), channel.getGbDeviceId()); + throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); + } + } + + @Override + public PageInfo queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType) { + PageHelper.startPage(page, count); + if (query != null) { + query = query.replaceAll("/", "//") + .replaceAll("%", "/%") + .replaceAll("_", "/_"); + } + List all = commonGBChannelMapper.queryListByCivilCodeForUnusual(query, online, channelType); + return new PageInfo<>(all); + } + + @Override + public void clearChannelCivilCode(Boolean all, List channelIds) { + + List channelIdsForClear; + if (all != null && all) { + channelIdsForClear = commonGBChannelMapper.queryAllForUnusualCivilCode(); + }else { + channelIdsForClear = channelIds; + } + commonGBChannelMapper.removeCivilCodeByChannelIds(channelIdsForClear); + } + + @Override + public PageInfo queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType) { + PageHelper.startPage(page, count); + if (query != null) { + query = query.replaceAll("/", "//") + .replaceAll("%", "/%") + .replaceAll("_", "/_"); + } + List all = commonGBChannelMapper.queryListByParentForUnusual(query, online, channelType); + return new PageInfo<>(all); + } + + @Override + public void clearChannelParent(Boolean all, List channelIds) { + List channelIdsForClear; + if (all != null && all) { + channelIdsForClear = commonGBChannelMapper.queryAllForUnusualParent(); + }else { + channelIdsForClear = channelIds; + } + commonGBChannelMapper.removeParentIdByChannelIds(channelIdsForClear); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GroupServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GroupServiceImpl.java index 3e79f7c4a..bc8e9f106 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GroupServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/GroupServiceImpl.java @@ -10,6 +10,7 @@ import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.gb28181.service.IGroupService; import com.genersoft.iot.vmp.utils.DateUtil; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.google.common.collect.Lists; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -47,6 +48,13 @@ public class GroupServiceImpl implements IGroupService { GbCode gbCode = GbCode.decode(group.getDeviceId()); Assert.notNull(gbCode, "设备编号不满足国标定义"); + + // 查询数据库中已经存在的. + List groupListInDb = groupManager.queryInGroupListByDeviceId(Lists.newArrayList(group)); + if (!ObjectUtils.isEmpty(groupListInDb)){ + throw new ControllerException(ErrorCode.ERROR100.getCode(), String.format("该节点编号 %s 已存在", group.getDeviceId())); + } + if ("215".equals(gbCode.getTypeCode())){ // 添加业务分组 addBusinessGroup(group); @@ -100,6 +108,12 @@ public class GroupServiceImpl implements IGroupService { Group groupInDb = groupManager.queryOne(group.getId()); Assert.notNull(groupInDb, "分组不存在"); + // 查询数据库中已经存在的. + List groupListInDb = groupManager.queryInGroupListByDeviceId(Lists.newArrayList(group)); + if (!ObjectUtils.isEmpty(groupListInDb) && groupListInDb.get(0).getId() != group.getId()){ + throw new ControllerException(ErrorCode.ERROR100.getCode(), String.format("该该节点编号 %s 已存在", group.getDeviceId())); + } + group.setName(group.getName()); group.setUpdateTime(DateUtil.getNow()); groupManager.update(group); @@ -209,7 +223,7 @@ public class GroupServiceImpl implements IGroupService { for (Platform platform : platformList) { try { // 发送catalog - eventPublisher.catalogEventPublish(platform.getId(), channel, CatalogEvent.DEL); + eventPublisher.catalogEventPublish(platform, channel, CatalogEvent.DEL); }catch (Exception e) { log.warn("[业务分组/虚拟组织删除] 发送失败,{}", groupForDelete.getDeviceId(), e); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/InviteStreamServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/InviteStreamServiceImpl.java index 4338bbfe5..c3c768072 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/InviteStreamServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/InviteStreamServiceImpl.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.gb28181.service.impl; import com.alibaba.fastjson2.JSON; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.Device; @@ -28,7 +27,6 @@ import java.util.concurrent.CopyOnWriteArrayList; @Slf4j @Service -@DS("master") public class InviteStreamServiceImpl implements IInviteStreamService { private final Map>> inviteErrorCallbackMap = new ConcurrentHashMap<>(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PTZServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PTZServiceImpl.java index 36f60510c..3fabadb2a 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PTZServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PTZServiceImpl.java @@ -1,14 +1,22 @@ package com.genersoft.iot.vmp.gb28181.service.impl; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.Preset; +import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IPTZService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.Assert; import javax.sip.InvalidArgumentException; import javax.sip.SipException; @@ -24,6 +32,18 @@ public class PTZServiceImpl implements IPTZService { @Autowired private SIPCommander cmder; + @Autowired + private UserSetting userSetting; + + @Autowired + private IRedisRpcPlayService redisRpcPlayService; + + @Autowired + private IDeviceChannelService deviceChannelService; + + @Autowired + private IDeviceService deviceService; + @Override public void ptz(Device device, String channelId, int cmdCode, int horizonSpeed, int verticalSpeed, int zoomSpeed) { @@ -37,6 +57,17 @@ public class PTZServiceImpl implements IPTZService { @Override public void frontEndCommand(Device device, String channelId, int cmdCode, int parameter1, int parameter2, int combindCode2) { + // 判断设备是否属于当前平台, 如果不属于则发起自动调用 + if (!userSetting.getServerId().equals(device.getServerId())) { + // 通道ID + DeviceChannel deviceChannel = deviceChannelService.getOneForSource(device.getDeviceId(), channelId); + Assert.notNull(deviceChannel, "通道不存在"); + String msg = redisRpcPlayService.frontEndCommand(device.getServerId(), deviceChannel.getId(), cmdCode, parameter1, parameter2, combindCode2); + if (msg != null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), msg); + } + return; + } try { cmder.frontEndCmd(device, channelId, cmdCode, parameter1, parameter2, combindCode2); } catch (SipException | InvalidArgumentException | ParseException e) { @@ -45,6 +76,21 @@ public class PTZServiceImpl implements IPTZService { } } + @Override + public void frontEndCommand(CommonGBChannel channel, Integer cmdCode, Integer parameter1, Integer parameter2, Integer combindCode2) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { + // 只有国标通道的支持云台控制 + log.warn("[INFO 消息] 只有国标通道的支持云台控制, 通道ID: {}", channel.getGbId()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "不支持"); + } + Device device = deviceService.getDevice(channel.getDataDeviceId()); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到设备ID"); + } + DeviceChannel deviceChannel = deviceChannelService.getOneById(channel.getGbId()); + frontEndCommand(device, deviceChannel.getDeviceId(), cmdCode, parameter1, parameter2, combindCode2); + } + @Override public List queryPresetList(String deviceId, String channelDeviceId) { return Collections.emptyList(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java index 2f768f10e..ff11f2ef7 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformChannelServiceImpl.java @@ -1,13 +1,12 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.dao.*; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommanderForPlatform; -import com.genersoft.iot.vmp.jt1078.proc.request.Re; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; @@ -26,7 +25,6 @@ import java.util.*; */ @Slf4j @Service -@DS("master") public class PlatformChannelServiceImpl implements IPlatformChannelService { @Autowired @@ -215,6 +213,10 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @Transactional public int addChannelList(Integer platformId, List channelList) { + Platform platform = platformMapper.query(platformId); + if (platform == null) { + return 0; + } int result = platformChannelMapper.addChannels(platformId, channelList); if (result > 0) { // 查询通道相关的行政区划信息是否共享,如果没共享就添加 @@ -244,7 +246,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platformId, channelList, CatalogEvent.ADD); + eventPublisher.catalogEventPublish(platform, channelList, CatalogEvent.ADD); } catch (Exception e) { log.warn("[关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -254,6 +256,11 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @Override public int removeAllChannel(Integer platformId) { + Platform platform = platformMapper.query(platformId); + if (platform == null) { + return 0; + } + List channelListShare = platformChannelMapper.queryShare(platformId, null); Assert.notEmpty(channelListShare, "未共享任何通道"); int result = platformChannelMapper.removeChannelsWithPlatform(platformId, channelListShare); @@ -278,7 +285,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platformId, channelListShare, CatalogEvent.DEL); + eventPublisher.catalogEventPublish(platform, channelListShare, CatalogEvent.DEL); } catch (Exception e) { log.warn("[移除全部关联通道] 发送失败,数量:{}", channelListShare.size(), e); } @@ -289,19 +296,23 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @Override @Transactional public void addChannelByDevice(Integer platformId, List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(ChannelDataType.GB28181.value, deviceIds); addChannels(platformId, channelList); } @Override @Transactional public void removeChannelByDevice(Integer platformId, List deviceIds) { - List channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(deviceIds); + List channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(ChannelDataType.GB28181.value, deviceIds); removeChannels(platformId, channelList); } @Transactional public int removeChannelList(Integer platformId, List channelList) { + Platform platform = platformMapper.query(platformId); + if (platform == null) { + return 0; + } int result = platformChannelMapper.removeChannelsWithPlatform(platformId, channelList); if (result > 0) { // 查询通道相关的分组信息 @@ -324,7 +335,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platformId, channelList, CatalogEvent.DEL); + eventPublisher.catalogEventPublish(platform, channelList, CatalogEvent.DEL); } catch (Exception e) { log.warn("[移除关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -425,14 +436,15 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { @Override public void updateCustomChannel(PlatformChannel channel) { platformChannelMapper.updateCustomChannel(channel); + Platform platform = platformMapper.query(channel.getPlatformId()); CommonGBChannel commonGBChannel = platformChannelMapper.queryShareChannel(channel.getPlatformId(), channel.getGbId()); // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(channel.getPlatformId(), commonGBChannel, CatalogEvent.UPDATE); + eventPublisher.catalogEventPublish(platform, commonGBChannel, CatalogEvent.UPDATE); } catch (Exception e) { log.warn("[自定义通道信息] 发送失败, 平台ID: {}, 通道: {}({})", channel.getPlatformId(), - channel.getGbName(), channel.getGbDeviceDbId(), e); + channel.getGbName(), channel.getId(), e); } } @@ -468,7 +480,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platform.getId(), channelListForEvent, CatalogEvent.DEL); + eventPublisher.catalogEventPublish(platform, channelListForEvent, CatalogEvent.DEL); } catch (Exception e) { log.warn("[移除关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -506,7 +518,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platform.getId(), channelListForEvent, CatalogEvent.DEL); + eventPublisher.catalogEventPublish(platform, channelListForEvent, CatalogEvent.DEL); } catch (Exception e) { log.warn("[移除关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -537,7 +549,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platform.getId(), channelListForEvent, CatalogEvent.ADD); + eventPublisher.catalogEventPublish(platform, channelListForEvent, CatalogEvent.ADD); } catch (Exception e) { log.warn("[移除关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -567,7 +579,7 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { // 发送消息 try { // 发送catalog - eventPublisher.catalogEventPublish(platform.getId(), channelListForEvent, CatalogEvent.ADD); + eventPublisher.catalogEventPublish(platform, channelListForEvent, CatalogEvent.ADD); } catch (Exception e) { log.warn("[移除关联通道] 发送失败,数量:{}", channelList.size(), e); } @@ -584,4 +596,9 @@ public class PlatformChannelServiceImpl implements IPlatformChannelService { public CommonGBChannel queryChannelByPlatformIdAndChannelId(Integer platformId, Integer channelId) { return platformChannelMapper.queryShareChannel(platformId, channelId); } + + @Override + public List queryChannelByPlatformIdAndChannelIds(Integer platformId, List channelIds) { + return platformChannelMapper.queryShare(platformId, channelIds); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java index 75228fc38..f76c0dc81 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlatformServiceImpl.java @@ -1,9 +1,9 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.conf.DynamicTask; +import com.genersoft.iot.vmp.conf.SipConfig; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.bean.*; @@ -26,6 +26,7 @@ import com.genersoft.iot.vmp.media.event.mediaServer.MediaSendRtpStoppedEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.bean.*; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.DateUtil; import com.github.pagehelper.PageHelper; @@ -35,6 +36,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -47,13 +49,13 @@ import java.text.ParseException; import java.util.List; import java.util.UUID; import java.util.Vector; +import java.util.concurrent.TimeUnit; /** * @author lin */ @Slf4j @Service -@DS("master") public class PlatformServiceImpl implements IPlatformService { private final static String REGISTER_KEY_PREFIX = "platform_register_"; @@ -67,6 +69,7 @@ public class PlatformServiceImpl implements IPlatformService { @Autowired private IRedisCatchStorage redisCatchStorage; + @Autowired private SSRCFactory ssrcFactory; @@ -85,6 +88,12 @@ public class PlatformServiceImpl implements IPlatformService { @Autowired private UserSetting userSetting; + @Autowired + private IRedisRpcService redisRpcService; + + @Autowired + private SipConfig sipConfig; + @Autowired private SipInviteSessionManager sessionManager; @@ -100,6 +109,85 @@ public class PlatformServiceImpl implements IPlatformService { @Autowired private ISendRtpServerService sendRtpServerService; + // 定时监听国标级联所进行的WVP服务是否正常, 如果异常则选择新的wvp执行 + @Scheduled(fixedDelay = 2, timeUnit = TimeUnit.SECONDS) //每3秒执行一次 + public void execute(){ + if (!userSetting.isAutoRegisterPlatform()) { + return; + } + // 查找非平台的国标级联执行服务Id + List serverIds = platformMapper.queryServerIdsWithEnableAndNotInServer(userSetting.getServerId()); + if (serverIds == null || serverIds.isEmpty()) { + return; + } + serverIds.forEach(serverId -> { + // 检查每个是否存活 + ServerInfo serverInfo = redisCatchStorage.queryServerInfo(serverId); + if (serverInfo != null) { + return; + } + log.info("[集群] 检测到 {} 已离线", serverId); + String chooseServerId = redisCatchStorage.chooseOneServer(serverId); + if (!userSetting.getServerId().equals(chooseServerId)){ + return; + } + // 此平台需要选择新平台处理, 确定由当前平台即开始处理 + List platformList = platformMapper.queryByServerId(serverId); + platformList.forEach(platform -> { + log.info("[集群] 由本平台开启上级平台{}({})的注册", platform.getName(), platform.getServerGBId()); + // 设置平台使用当前平台的IP + platform.setAddress(getIpWithSameNetwork(platform.getAddress())); + platform.setServerId(userSetting.getServerId()); + platformMapper.update(platform); + // 更新redis + redisCatchStorage.delPlatformCatchInfo(platform.getServerGBId()); + PlatformCatch platformCatch = new PlatformCatch(); + platformCatch.setPlatform(platform); + platformCatch.setId(platform.getServerGBId()); + redisCatchStorage.updatePlatformCatchInfo(platformCatch); + // 开始注册 + // 注册成功时由程序直接调用了online方法 + try { + commanderForPlatform.register(platform, eventResult -> { + log.info("[国标级联] {}({}),添加向上级注册失败,请确定上级平台可用时重新保存", platform.getName(), platform.getServerGBId()); + }, null); + } catch (InvalidArgumentException | ParseException | SipException e) { + log.error("[命令发送失败] 国标级联: {}", e.getMessage()); + } + }); + }); + } + + /** + * 获取同网段的IP + */ + private String getIpWithSameNetwork(String ip){ + if (ip == null || sipConfig.getMonitorIps().size() == 1) { + return sipConfig.getMonitorIps().get(0); + } + String[] ipSplit = ip.split("\\."); + String ip1 = null, ip2 = null, ip3 = null; + for (String monitorIp : sipConfig.getMonitorIps()) { + String[] monitorIpSplit = monitorIp.split("\\."); + if (monitorIpSplit[0].equals(ipSplit[0]) && monitorIpSplit[1].equals(ipSplit[1]) && monitorIpSplit[2].equals(ipSplit[2])) { + ip3 = monitorIp; + }else if (monitorIpSplit[0].equals(ipSplit[0]) && monitorIpSplit[1].equals(ipSplit[1])) { + ip2 = monitorIp; + }else if (monitorIpSplit[0].equals(ipSplit[0])) { + ip1 = monitorIp; + } + } + if (ip3 != null) { + return ip3; + }else if (ip2 != null) { + return ip2; + }else if (ip1 != null) { + return ip1; + }else { + return sipConfig.getMonitorIps().get(0); + } + } + /** * 流离开的处理 */ @@ -175,6 +263,7 @@ public class PlatformServiceImpl implements IPlatformService { // 每次发送目录的数量默认为1 platform.setCatalogGroup(1); } + platform.setServerId(userSetting.getServerId()); int result = platformMapper.add(platform); // 添加缓存 PlatformCatch platformCatch = new PlatformCatch(); @@ -201,6 +290,11 @@ public class PlatformServiceImpl implements IPlatformService { log.info("[国标级联] 更新平台 {}({})", platform.getName(), platform.getDeviceGBId()); platform.setCharacterSet(platform.getCharacterSet().toUpperCase()); Platform platformInDb = platformMapper.query(platform.getId()); + Assert.notNull(platformInDb, "平台不存在"); + if (!userSetting.getServerId().equals(platformInDb.getServerId())) { + return redisRpcService.updatePlatform(platformInDb.getServerId(), platform); + } + PlatformCatch platformCatchOld = redisCatchStorage.queryPlatformCatchInfo(platformInDb.getServerGBId()); platform.setUpdateTime(DateUtil.getNow()); @@ -543,7 +637,7 @@ public class PlatformServiceImpl implements IPlatformService { // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(platform.getServerGBId(), channel.getGbId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort(), userSetting.getBroadcastForPlatform(), InviteSessionType.BROADCAST, - InviteSessionStatus.ready); + InviteSessionStatus.ready, userSetting.getRecordSip()); inviteStreamService.updateInviteInfo(inviteInfo); String timeOutTaskKey = UUID.randomUUID().toString(); dynamicTask.startDelay(timeOutTaskKey, () -> { @@ -553,14 +647,14 @@ public class PlatformServiceImpl implements IPlatformService { log.info("[国标级联] 发起语音喊话 收流超时 deviceId: {}, channelId: {},端口:{}, SSRC: {}", platform.getServerGBId(), channel.getGbDeviceId(), ssrcInfo.getPort(), ssrcInfo.getSsrc()); // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 try { - commanderForPlatform.streamByeCmd(platform, channel, ssrcInfo.getStream(), null, null); + commanderForPlatform.streamByeCmd(platform, channel, ssrcInfo.getApp(), ssrcInfo.getStream(), null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[点播超时], 发送BYE失败 {}", e.getMessage()); } finally { timeoutCallback.run(1, "收流超时"); mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); mediaServerService.closeRTPServer(mediaServerItem, ssrcInfo.getStream()); } } @@ -590,7 +684,7 @@ public class PlatformServiceImpl implements IPlatformService { StreamInfo streamInfo = mediaServerService.getStreamInfoByAppAndStream(mediaServerItem, mediaInfo.getApp(), mediaInfo.getStream(), mediaInfo, null); streamInfo.setChannelId(channel.getGbId()); - InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getGbId()); + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.BROADCAST, channel.getGbId()); if (inviteInfo != null) { inviteInfo.setStatus(InviteSessionStatus.ok); inviteInfo.setStreamInfo(streamInfo); @@ -638,7 +732,7 @@ public class PlatformServiceImpl implements IPlatformService { if (!result) { try { log.warn("[Invite 200OK] 更新ssrc失败,停止喊话 {}/{}", platform.getServerGBId(), channel.getGbDeviceId()); - commanderForPlatform.streamByeCmd(platform, channel, ssrcInfo.getStream(), null, null); + commanderForPlatform.streamByeCmd(platform, channel, ssrcInfo.getApp(), ssrcInfo.getStream(), null, null); } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { log.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage()); } @@ -647,7 +741,7 @@ public class PlatformServiceImpl implements IPlatformService { // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(), "下级自定义了ssrc,重新设置收流信息失败", null); @@ -687,12 +781,13 @@ public class PlatformServiceImpl implements IPlatformService { if (ssrcInResponse != null) { // 单端口 // 重新订阅流上线 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(inviteInfo.getStream()); - sessionManager.removeByStream(inviteInfo.getStream()); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(ssrcInfo.getApp(), inviteInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), inviteInfo.getStream()); inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse); ssrcTransaction.setPlatformId(platform.getServerGBId()); ssrcTransaction.setChannelId(channel.getGbId()); + ssrcTransaction.setApp(ssrcInfo.getApp()); ssrcTransaction.setStream(inviteInfo.getStream()); ssrcTransaction.setSsrc(ssrcInResponse); ssrcTransaction.setMediaServerId(mediaServerItem.getId()); @@ -744,7 +839,7 @@ public class PlatformServiceImpl implements IPlatformService { // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(), InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null); @@ -755,11 +850,11 @@ public class PlatformServiceImpl implements IPlatformService { } @Override - public void stopBroadcast(Platform platform, CommonGBChannel channel, String stream, boolean sendBye, MediaServer mediaServerItem) { + public void stopBroadcast(Platform platform, CommonGBChannel channel, String app, String stream, boolean sendBye, MediaServer mediaServerItem) { try { if (sendBye) { - commanderForPlatform.streamByeCmd(platform, channel, stream, null, null); + commanderForPlatform.streamByeCmd(platform, channel, app, stream, null, null); } } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { log.warn("[消息发送失败] 停止语音对讲, 平台:{},通道:{}", platform.getId(), channel.getGbDeviceId() ); @@ -771,7 +866,7 @@ public class PlatformServiceImpl implements IPlatformService { mediaServerService.releaseSsrc(mediaServerItem.getId(), inviteInfo.getSsrcInfo().getSsrc()); inviteStreamService.removeInviteInfo(inviteInfo); } - sessionManager.removeByStream(stream); + sessionManager.removeByStream(app, stream); } } @@ -781,8 +876,8 @@ public class PlatformServiceImpl implements IPlatformService { } @Override - public List queryEnablePlatformList() { - return platformMapper.queryEnablePlatformList(); + public List queryEnablePlatformList(String serverId) { + return platformMapper.queryEnableParentPlatformList(serverId,true); } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java index 645a4b949..95e2e7905 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/PlayServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.gb28181.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.InviteInfo; import com.genersoft.iot.vmp.common.*; import com.genersoft.iot.vmp.conf.DynamicTask; @@ -32,6 +31,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.service.IReceiveRtpServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService; import com.genersoft.iot.vmp.service.bean.*; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.utils.CloudRecordUtils; import com.genersoft.iot.vmp.utils.DateUtil; @@ -64,8 +64,7 @@ import java.util.Vector; @SuppressWarnings(value = {"rawtypes", "unchecked"}) @Slf4j -@Service -@DS("master") +@Service("playService") public class PlayServiceImpl implements IPlayService { @Autowired @@ -125,6 +124,9 @@ public class PlayServiceImpl implements IPlayService { @Autowired private ICloudRecordService cloudRecordService; + @Autowired + private IRedisRpcPlayService redisRpcPlayService; + /** * 流到来的处理 */ @@ -188,7 +190,7 @@ public class PlayServiceImpl implements IPlayService { DeviceChannel channel = deviceChannelService.getOneById(sendRtpInfo.getChannelId()); try { if (device != null && channel != null) { - cmder.streamByeCmd(device, channel.getDeviceId(), event.getStream(), sendRtpInfo.getCallId()); + cmder.streamByeCmd(device, channel.getDeviceId(), event.getApp(), event.getStream(), sendRtpInfo.getCallId(), null); if (sendRtpInfo.getPlayType().equals(InviteStreamType.BROADCAST) || sendRtpInfo.getPlayType().equals(InviteStreamType.TALK)) { AudioBroadcastCatch audioBroadcastCatch = audioBroadcastManager.get(channel.getId()); @@ -287,6 +289,21 @@ public class PlayServiceImpl implements IPlayService { } } + @Override + public void play(Device device, DeviceChannel channel, ErrorCallback callback) { + + // 判断设备是否属于当前平台, 如果不属于则发起自动调用 + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.play(device.getServerId(), channel.getId(), callback); + return; + } + MediaServer mediaServerItem = getNewMediaServerItem(device); + if (mediaServerItem == null) { + log.warn("[点播] 未找到可用的zlm deviceId: {},channelId:{}", device.getDeviceId(), channel.getDeviceId()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的zlm"); + } + play(mediaServerItem, device, channel, null, userSetting.getRecordSip(), callback); + } @Override public SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback callback) { @@ -305,11 +322,11 @@ public class PlayServiceImpl implements IPlayService { throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到通道"); } - return play(mediaServerItem, device, channel, ssrc, callback); + return play(mediaServerItem, device, channel, ssrc, userSetting.getRecordSip(), callback); } - private SSRCInfo play(MediaServer mediaServerItem, Device device, DeviceChannel channel, String ssrc, - ErrorCallback callback) { + private SSRCInfo play(MediaServer mediaServerItem, Device device, DeviceChannel channel, String ssrc, Boolean record, + ErrorCallback callback) { if (mediaServerItem == null ) { if (callback != null) { callback.run(InviteErrorCode.ERROR_FOR_PARAMETER_ERROR.getCode(), @@ -322,11 +339,12 @@ public class PlayServiceImpl implements IPlayService { InviteInfo inviteInfoInCatch = inviteStreamService.getInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); if (inviteInfoInCatch != null ) { if (inviteInfoInCatch.getStreamInfo() == null) { - // 释放生成的ssrc,使用上一次申请的 + // 释放生成的ssrc,使用上一次申请的322 + ssrcFactory.releaseSsrc(mediaServerItem.getId(), ssrc); // 点播发起了但是尚未成功, 仅注册回调等待结果即可 inviteStreamService.once(InviteSessionType.PLAY, channel.getId(), null, callback); - log.info("[点播开始] 已经请求中,等待结果, deviceId: {}, channelId: {}", device.getDeviceId(), channel.getDeviceId()); + log.info("[点播开始] 已经请求中,等待结果, deviceId: {}, channelId({}): {}", device.getDeviceId(), channel.getDeviceId(), channel.getId()); return inviteInfoInCatch.getSsrcInfo(); }else { StreamInfo streamInfo = inviteInfoInCatch.getStreamInfo(); @@ -372,6 +390,7 @@ public class PlayServiceImpl implements IPlayService { rtpServerParam.setTcpMode(tcpMode); rtpServerParam.setOnlyAuto(false); rtpServerParam.setDisableAudio(!channel.isHasAudio()); + SSRCInfo ssrcInfo = receiveRtpServerService.openRTPServer(rtpServerParam, (code, msg, result) -> { if (code == InviteErrorCode.SUCCESS.getCode() && result != null && result.getHookData() != null) { @@ -404,14 +423,14 @@ public class PlayServiceImpl implements IPlayService { } inviteStreamService.call(InviteSessionType.PLAY, channel.getId(), null, code, msg, null); inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, channel.getId()); - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(streamId); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream("rtp", streamId); if (ssrcTransaction != null) { try { - cmder.streamByeCmd(device, channel.getDeviceId(), streamId, null); + cmder.streamByeCmd(device, channel.getDeviceId(),"rtp", streamId, null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[点播超时], 发送BYE失败 {}", e.getMessage()); } finally { - sessionManager.removeByStream(streamId); + sessionManager.removeByStream("rtp", streamId); } } } @@ -425,14 +444,20 @@ public class PlayServiceImpl implements IPlayService { null); return null; } - log.info("[点播开始] deviceId: {}, channelId: {},码流类型:{}, 收流端口: {}, 码流:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", - device.getDeviceId(), channel.getDeviceId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(), + log.info("[点播开始] deviceId: {}, channelId({}): {},码流类型:{}, 收流端口: {}, 码流:{}, 收流模式:{}, SSRC: {}, SSRC校验:{}", + device.getDeviceId(), channel.getDeviceId(), channel.getId(), channel.getStreamIdentification(), ssrcInfo.getPort(), ssrcInfo.getStream(), device.getStreamMode(), ssrcInfo.getSsrc(), device.isSsrcCheck()); // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAY, - InviteSessionStatus.ready); + InviteSessionStatus.ready, userSetting.getRecordSip()); + if (record != null) { + inviteInfo.setRecord(record); + }else { + inviteInfo.setRecord(userSetting.getRecordSip()); + } + inviteStreamService.updateInviteInfo(inviteInfo); try { @@ -443,7 +468,7 @@ public class PlayServiceImpl implements IPlayService { log.info("[点播失败]{}:{} deviceId: {}, channelId:{}",event.statusCode, event.msg, device.getDeviceId(), channel.getDeviceId()); receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); if (callback != null) { callback.run(event.statusCode, event.msg, null); } @@ -455,7 +480,7 @@ public class PlayServiceImpl implements IPlayService { } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 点播消息: {}", e.getMessage()); receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); if (callback != null) { callback.run(InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getCode(), InviteErrorCode.ERROR_FOR_SIP_SENDING_FAILED.getMsg(), null); @@ -506,13 +531,13 @@ public class PlayServiceImpl implements IPlayService { timeoutCallback.run(); // 点播超时回复BYE 同时释放ssrc以及此次点播的资源 try { - cmder.streamByeCmd(device, channel.getDeviceId(), stream, null); + cmder.streamByeCmd(device, channel.getDeviceId(), null, null, callId, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[语音对讲]超时, 发送BYE失败 {}", e.getMessage()); } finally { timeoutCallback.run(); mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrc()); - sessionManager.removeByStream(sendRtpInfo.getStream()); + sessionManager.removeByStream(sendRtpInfo.getApp(), sendRtpInfo.getStream()); } }, userSetting.getPlayTimeout()); @@ -521,7 +546,7 @@ public class PlayServiceImpl implements IPlayService { if (localPort == null || localPort <= 0) { timeoutCallback.run(); mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrc()); - sessionManager.removeByStream(sendRtpInfo.getStream()); + sessionManager.removeByStream(sendRtpInfo.getApp(), sendRtpInfo.getStream()); return; } sendRtpInfo.setPort(localPort); @@ -556,7 +581,7 @@ public class PlayServiceImpl implements IPlayService { sendRtpInfo.setCallId(response.getCallIdHeader().getCallId()); sendRtpServerService.update(sendRtpInfo); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), sendRtpInfo.getChannelId(), "talk", + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), sendRtpInfo.getChannelId(), "talk", sendRtpInfo.getApp(), sendRtpInfo.getStream(), sendRtpInfo.getSsrc(), sendRtpInfo.getMediaServerId(), response, InviteSessionType.TALK); @@ -573,7 +598,7 @@ public class PlayServiceImpl implements IPlayService { mediaServerService.closeRTPServer(mediaServerItem, sendRtpInfo.getStream()); // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrc()); - sessionManager.removeByStream(sendRtpInfo.getStream()); + sessionManager.removeByStream(sendRtpInfo.getApp(), sendRtpInfo.getStream()); errorEvent.response(event); }, userSetting.getPlayTimeout().longValue()); } catch (InvalidArgumentException | SipException | ParseException e) { @@ -584,7 +609,7 @@ public class PlayServiceImpl implements IPlayService { // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpInfo.getSsrc()); - sessionManager.removeByStream(sendRtpInfo.getStream()); + sessionManager.removeByStream(sendRtpInfo.getApp(), sendRtpInfo.getStream()); SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult(); eventResult.type = SipSubscribe.EventResultType.cmdSendFailEvent; eventResult.statusCode = -1; @@ -627,7 +652,7 @@ public class PlayServiceImpl implements IPlayService { if (!result) { // 主动连接失败,结束流程, 清理数据 receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(), InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null); inviteStreamService.call(InviteSessionType.BROADCAST, channel.getId(), null, @@ -638,7 +663,7 @@ public class PlayServiceImpl implements IPlayService { log.error("[TCP主动连接对方] deviceId: {}, channelId: {}, 解析200OK的SDP信息失败", device.getDeviceId(), channel.getDeviceId(), e); receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); callback.run(InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getCode(), InviteErrorCode.ERROR_FOR_SDP_PARSING_EXCEPTIONS.getMsg(), null); @@ -729,6 +754,11 @@ public class PlayServiceImpl implements IPlayService { if (channel == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "通道不存在"); } + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.playback(device.getServerId(), channel.getId(), startTime, endTime, callback); + return; + } + MediaServer newMediaServerItem = getNewMediaServerItem(device); if (newMediaServerItem == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的节点"); @@ -782,14 +812,14 @@ public class PlayServiceImpl implements IPlayService { } inviteStreamService.call(InviteSessionType.PLAYBACK, channel.getId(), null, code, msg, null); inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAYBACK, channel.getId()); - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream("rtp", stream); if (ssrcTransaction != null) { try { - cmder.streamByeCmd(device, channel.getDeviceId(), stream, null); + cmder.streamByeCmd(device, channel.getDeviceId(),"rtp", stream, null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[录像回放] 发送BYE失败 {}", e.getMessage()); } finally { - sessionManager.removeByStream(stream); + sessionManager.removeByStream("rtp", stream); } } } @@ -812,7 +842,7 @@ public class PlayServiceImpl implements IPlayService { // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.PLAYBACK, - InviteSessionStatus.ready); + InviteSessionStatus.ready, userSetting.getRecordSip()); inviteStreamService.updateInviteInfo(inviteInfo); try { @@ -828,7 +858,7 @@ public class PlayServiceImpl implements IPlayService { } receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); }, userSetting.getPlayTimeout().longValue()); } catch (InvalidArgumentException | SipException | ParseException e) { @@ -837,7 +867,7 @@ public class PlayServiceImpl implements IPlayService { callback.run(InviteErrorCode.FAIL.getCode(), e.getMessage(), null); } receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); } } @@ -883,7 +913,7 @@ public class PlayServiceImpl implements IPlayService { if (!result) { try { log.warn("[Invite 200OK] 更新ssrc失败,停止点播 {}/{}", device.getDeviceId(), channel.getDeviceId()); - cmder.streamByeCmd(device, channel.getDeviceId(), ssrcInfo.getStream(), null, null); + cmder.streamByeCmd(device, channel.getDeviceId(), ssrcInfo.getApp(), ssrcInfo.getStream(), null, null); } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { log.error("[命令发送失败] 停止播放, 发送BYE: {}", e.getMessage()); } @@ -891,7 +921,7 @@ public class PlayServiceImpl implements IPlayService { // 释放ssrc mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); callback.run(InviteErrorCode.ERROR_FOR_RESET_SSRC.getCode(), "下级自定义了ssrc,重新设置收流信息失败", null); @@ -917,13 +947,15 @@ public class PlayServiceImpl implements IPlayService { if (ssrcInResponse != null) { // 单端口 // 重新订阅流上线 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(inviteInfo.getStream()); - sessionManager.removeByStream(inviteInfo.getStream()); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream("rtp", inviteInfo.getStream()); + sessionManager.removeByStream("rtp", inviteInfo.getStream()); inviteStreamService.updateInviteInfoForSSRC(inviteInfo, ssrcInResponse); ssrcTransaction.setDeviceId(device.getDeviceId()); ssrcTransaction.setChannelId(ssrcTransaction.getChannelId()); ssrcTransaction.setCallId(ssrcTransaction.getCallId()); ssrcTransaction.setSsrc(ssrcInResponse); + ssrcTransaction.setApp("rtp"); + ssrcTransaction.setStream(inviteInfo.getStream()); ssrcTransaction.setMediaServerId(mediaServerItem.getId()); ssrcTransaction.setSipTransactionInfo(new SipTransactionInfo((SIPResponse) responseEvent.getResponse())); ssrcTransaction.setType(inviteSessionType); @@ -937,6 +969,11 @@ public class PlayServiceImpl implements IPlayService { @Override public void download(Device device, DeviceChannel channel, String startTime, String endTime, int downloadSpeed, ErrorCallback callback) { + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.download(device.getServerId(), channel.getId(), startTime, endTime, downloadSpeed, callback); + return; + } + MediaServer newMediaServerItem = this.getNewMediaServerItem(device); if (newMediaServerItem == null) { callback.run(InviteErrorCode.ERROR_FOR_ASSIST_NOT_READY.getCode(), @@ -986,14 +1023,14 @@ public class PlayServiceImpl implements IPlayService { inviteStreamService.call(InviteSessionType.DOWNLOAD, channel.getId(), null, code, msg, null); inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.DOWNLOAD, channel.getId()); if (result != null && result.getSsrcInfo() != null) { - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(result.getSsrcInfo().getStream()); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(result.getSsrcInfo().getApp(), result.getSsrcInfo().getStream()); if (ssrcTransaction != null) { try { - cmder.streamByeCmd(device, channel.getDeviceId(), ssrcTransaction.getStream(), null); + cmder.streamByeCmd(device, channel.getDeviceId(), ssrcTransaction.getApp(), ssrcTransaction.getStream(), null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[录像下载] 发送BYE失败 {}", e.getMessage()); } finally { - sessionManager.removeByStream(ssrcTransaction.getStream()); + sessionManager.removeByStream(ssrcTransaction.getApp(), ssrcTransaction.getStream()); } } } @@ -1018,7 +1055,9 @@ public class PlayServiceImpl implements IPlayService { // 初始化redis中的invite消息状态 InviteInfo inviteInfo = InviteInfo.getInviteInfo(device.getDeviceId(), channel.getId(), ssrcInfo.getStream(), ssrcInfo, mediaServerItem.getId(), mediaServerItem.getSdpIp(), ssrcInfo.getPort(), device.getStreamMode(), InviteSessionType.DOWNLOAD, - InviteSessionStatus.ready); + InviteSessionStatus.ready, true); + inviteInfo.setStartTime(startTime); + inviteInfo.setEndTime(endTime); inviteStreamService.updateInviteInfo(inviteInfo); try { @@ -1027,7 +1066,7 @@ public class PlayServiceImpl implements IPlayService { // 对方返回错误 callback.run(InviteErrorCode.FAIL.getCode(), String.format("录像下载失败, 错误码: %s, %s", eventResult.statusCode, eventResult.msg), null); receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); }, eventResult ->{ // 处理收到200ok后的TCP主动连接以及SSRC不一致的问题 @@ -1059,13 +1098,15 @@ public class PlayServiceImpl implements IPlayService { log.error("[命令发送失败] 录像下载: {}", e.getMessage()); callback.run(InviteErrorCode.FAIL.getCode(),e.getMessage(), null); receiveRtpServerService.closeRTPServer(mediaServerItem, ssrcInfo); - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); inviteStreamService.removeInviteInfo(inviteInfo); } } @Override public StreamInfo getDownLoadInfo(Device device, DeviceChannel channel, String stream) { + + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channel.getId(), stream); if (inviteInfo == null) { String app = "rtp"; @@ -1195,8 +1236,8 @@ public class PlayServiceImpl implements IPlayService { continue; } try { - cmder.streamByeCmd(device, deviceChannel.getDeviceId(), - ssrcTransaction.getStream(), null); + cmder.streamByeCmd(device, deviceChannel.getDeviceId(), ssrcTransaction.getApp(), + ssrcTransaction.getStream(), null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[zlm离线]为正在使用此zlm的设备, 发送BYE失败 {}", e.getMessage()); @@ -1207,10 +1248,19 @@ public class PlayServiceImpl implements IPlayService { } @Override - public AudioBroadcastResult audioBroadcast(Device device, DeviceChannel deviceChannel, Boolean broadcastMode) { - // TODO 必须多端口模式才支持语音喊话鹤语音对讲 - if (device == null || deviceChannel == null) { - return null; + public AudioBroadcastResult audioBroadcast(String deviceId, String channelDeviceId, Boolean broadcastMode) { + + Device device = deviceService.getDeviceByDeviceId(deviceId); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到设备: " + deviceId); + } + DeviceChannel deviceChannel = deviceChannelService.getOne(deviceId, channelDeviceId); + if (deviceChannel == null) { + throw new ControllerException(ErrorCode.ERROR400.getCode(), "未找到通道: " + channelDeviceId); + } + + if (!userSetting.getServerId().equals(device.getServerId())) { + return redisRpcPlayService.audioBroadcast(device.getServerId(), deviceId, channelDeviceId, broadcastMode); } log.info("[语音喊话] device: {}, channel: {}", device.getDeviceId(), deviceChannel.getDeviceId()); MediaServer mediaServerItem = mediaServerService.getMediaServerForMinimumLoad(null); @@ -1342,11 +1392,20 @@ public class PlayServiceImpl implements IPlayService { @Override public void pauseRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { + InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); if (null == inviteInfo || inviteInfo.getStreamInfo() == null) { - log.warn("streamId不存在!"); - throw new ServiceException("streamId不存在"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "streamId不存在"); } + Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId()); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备不存在"); + } + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.pauseRtp(device.getServerId(), streamId); + return; + } + inviteInfo.getStreamInfo().setPause(true); inviteStreamService.updateInviteInfo(inviteInfo); MediaServer mediaServerItem = inviteInfo.getStreamInfo().getMediaServer(); @@ -1364,7 +1423,7 @@ public class PlayServiceImpl implements IPlayService { if (!result) { throw new ServiceException("暂停RTP接收失败"); } - Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId()); + DeviceChannel channel = deviceChannelService.getOneById(inviteInfo.getChannelId()); cmder.playPauseCmd(device, channel, inviteInfo.getStreamInfo()); } @@ -1373,9 +1432,17 @@ public class PlayServiceImpl implements IPlayService { public void resumeRtp(String streamId) throws ServiceException, InvalidArgumentException, ParseException, SipException { InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(InviteSessionType.PLAYBACK, streamId); if (null == inviteInfo || inviteInfo.getStreamInfo() == null) { - log.warn("streamId不存在!"); - throw new ServiceException("streamId不存在"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "streamId不存在"); } + Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId()); + if (device == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "设备不存在"); + } + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.resumeRtp(device.getServerId(), streamId); + return; + } + inviteInfo.getStreamInfo().setPause(false); inviteStreamService.updateInviteInfo(inviteInfo); MediaServer mediaServerItem = inviteInfo.getStreamInfo().getMediaServer(); @@ -1383,7 +1450,6 @@ public class PlayServiceImpl implements IPlayService { log.warn("mediaServer 不存在!"); throw new ServiceException("mediaServer不存在"); } - // zlm 暂停RTP超时检查 // 使用zlm中的流ID String streamKey = inviteInfo.getStream(); if (!mediaServerItem.isRtpEnable()) { @@ -1393,7 +1459,6 @@ public class PlayServiceImpl implements IPlayService { if (!result) { throw new ServiceException("继续RTP接收失败"); } - Device device = deviceService.getDeviceByDeviceId(inviteInfo.getDeviceId()); DeviceChannel channel = deviceChannelService.getOneById(inviteInfo.getChannelId()); cmder.playResumeCmd(device, channel, inviteInfo.getStreamInfo()); } @@ -1530,10 +1595,10 @@ public class PlayServiceImpl implements IPlayService { ssrcFactory.releaseSsrc(mediaServerId, sendRtpInfo.getSsrc()); - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(sendRtpInfo.getStream()); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(sendRtpInfo.getApp(), sendRtpInfo.getStream()); if (ssrcTransaction != null) { try { - cmder.streamByeCmd(device, channel.getDeviceId(), sendRtpInfo.getStream(), null); + cmder.streamByeCmd(device, channel.getDeviceId(), sendRtpInfo.getApp(), sendRtpInfo.getStream(), null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.info("[语音对讲] 停止消息发送失败,可能已经停止"); } @@ -1589,30 +1654,34 @@ public class PlayServiceImpl implements IPlayService { @Override public void stop(InviteSessionType type, Device device, DeviceChannel channel, String stream) { - InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream); - if (inviteInfo == null) { - if (type == InviteSessionType.PLAY) { + if (!userSetting.getServerId().equals(device.getServerId())) { + redisRpcPlayService.stop(device.getServerId(), type, channel.getId(), stream); + }else { + InviteInfo inviteInfo = inviteStreamService.getInviteInfo(type, channel.getId(), stream); + if (inviteInfo == null) { + if (type == InviteSessionType.PLAY) { + deviceChannelService.stopPlay(channel.getId()); + } + return; + } + inviteStreamService.removeInviteInfo(inviteInfo); + if (InviteSessionStatus.ok == inviteInfo.getStatus()) { + try { + log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); + cmder.streamByeCmd(device, channel.getDeviceId(), "rtp", inviteInfo.getStream(), null, null); + } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { + log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); + throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + } + } + + if (inviteInfo.getType() == InviteSessionType.PLAY) { deviceChannelService.stopPlay(channel.getId()); } - return; - } - inviteStreamService.removeInviteInfo(inviteInfo); - if (InviteSessionStatus.ok == inviteInfo.getStatus()) { - try { - log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); - cmder.streamByeCmd(device, channel.getDeviceId(), inviteInfo.getStream(), null, null); - } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { - log.error("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); - throw new ControllerException(ErrorCode.ERROR100.getCode(), "命令发送失败: " + e.getMessage()); + if (inviteInfo.getStreamInfo() != null) { + receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), inviteInfo.getSsrcInfo()); } } - - if (inviteInfo.getType() == InviteSessionType.PLAY) { - deviceChannelService.stopPlay(channel.getId()); - } - if (inviteInfo.getStreamInfo() != null) { - receiveRtpServerService.closeRTPServer(inviteInfo.getStreamInfo().getMediaServer(), inviteInfo.getSsrcInfo()); - } } @Override @@ -1623,7 +1692,7 @@ public class PlayServiceImpl implements IPlayService { log.warn("[停止点播] 发现通道不存在"); return; } - Device device = deviceService.getDevice(channel.getDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { log.warn("[停止点播] 发现设备不存在"); return; @@ -1632,7 +1701,7 @@ public class PlayServiceImpl implements IPlayService { if (InviteSessionStatus.ok == inviteInfo.getStatus()) { try { log.info("[停止点播/回放/下载] {}/{}", device.getDeviceId(), channel.getDeviceId()); - cmder.streamByeCmd(device, channel.getDeviceId(), inviteInfo.getStream(), null, null); + cmder.streamByeCmd(device, channel.getDeviceId(), "rtp", inviteInfo.getStream(), null, null); } catch (InvalidArgumentException | SipException | ParseException | SsrcTransactionNotFoundException e) { log.warn("[命令发送失败] 停止点播/回放/下载, 发送BYE: {}", e.getMessage()); } @@ -1647,19 +1716,25 @@ public class PlayServiceImpl implements IPlayService { } @Override - public void play(CommonGBChannel channel, ErrorCallback callback) { - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + public void play(CommonGBChannel channel, Boolean record, ErrorCallback callback) { + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { log.warn("[点播] 未找到通道{}的设备信息", channel); throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); } - MediaServer mediaServer = getNewMediaServerItem(device); - if (mediaServer == null) { - log.warn("[点播] 未找到可用媒体节点"); + DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); + play(device, deviceChannel, callback); + } + + @Override + public void stop(InviteSessionType inviteSessionType, CommonGBChannel channel, String stream) { + Device device = deviceService.getDevice(channel.getDataDeviceId()); + if (device == null) { + log.warn("[停止播放] 未找到通道{}的设备信息", channel); throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); } DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); - play(mediaServer, device, deviceChannel, null, callback); + stop(inviteSessionType, device, deviceChannel, stream); } @Override @@ -1668,7 +1743,7 @@ public class PlayServiceImpl implements IPlayService { throw new PlayException(Response.BAD_REQUEST, "bad request"); } // 国标通道 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { log.warn("[点播] 未找到通道{}的设备信息", channel); throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); @@ -1689,7 +1764,7 @@ public class PlayServiceImpl implements IPlayService { throw new PlayException(Response.BAD_REQUEST, "bad request"); } // 国标通道 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { log.warn("[点播] 未找到通道{}的设备信息", channel); throw new PlayException(Response.SERVER_INTERNAL_ERROR, "server internal error"); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java index f40d8c429..b21832a73 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/service/impl/RegionServiceImpl.java @@ -262,4 +262,66 @@ public class RegionServiceImpl implements IRegionService { regionList.addAll(allParent); return regionList; } + + @Override + public String getDescription(String civilCode) { + + CivilCodePo civilCodePo = CivilCodeUtil.INSTANCE.getCivilCodePo(civilCode); + Assert.notNull(civilCodePo, String.format("节点%s未查询到", civilCode)); + StringBuilder sb = new StringBuilder(); + sb.append(civilCodePo.getName()); + List civilCodePoList = CivilCodeUtil.INSTANCE.getAllParentCode(civilCode); + if (civilCodePoList.isEmpty()) { + return sb.toString(); + } + for (int i = 0; i < civilCodePoList.size(); i++) { + CivilCodePo item = civilCodePoList.get(i); + sb.insert(0, item.getName()); + if (i != civilCodePoList.size() - 1) { + sb.insert(0, "/"); + } + } + return sb.toString(); + } + + @Override + @Transactional + public void addByCivilCode(String civilCode) { + CivilCodePo civilCodePo = CivilCodeUtil.INSTANCE.getCivilCodePo(civilCode); + // 查询是否已经存在此节点 + Assert.notNull(civilCodePo, String.format("节点%s未查询到", civilCode)); + List civilCodePoList = CivilCodeUtil.INSTANCE.getAllParentCode(civilCode); + civilCodePoList.add(civilCodePo); + + Set civilCodeSet = regionMapper.queryInCivilCodePoList(civilCodePoList); + if (!civilCodeSet.isEmpty()) { + civilCodePoList.removeIf(item -> civilCodeSet.contains(item.getCode())); + } + if (civilCodePoList.isEmpty()) { + return; + } + int parentId = -1; + for (int i = civilCodePoList.size() - 1; i > -1; i--) { + CivilCodePo codePo = civilCodePoList.get(i); + + Region region = new Region(); + region.setDeviceId(codePo.getCode()); + region.setParentDeviceId(codePo.getParentCode()); + region.setName(civilCodePo.getName()); + region.setCreateTime(DateUtil.getNow()); + region.setUpdateTime(DateUtil.getNow()); + if (parentId == -1 && codePo.getParentCode() != null) { + Region parentRegion = regionMapper.queryByDeviceId(codePo.getParentCode()); + if (parentRegion == null){ + log.error(String.format("行政区划%sy已存在,但查询错误", codePo.getParentCode())); + throw new ControllerException(ErrorCode.ERROR100.getCode(), String.format("行政区划%sy已存在,但查询错误", codePo.getParentCode())); + } + region.setParentId(parentRegion.getId()); + }else { + region.setParentId(parentId); + } + regionMapper.add(region); + parentId = region.getId(); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java deleted file mode 100755 index 3f24dbee4..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/RecordDataCatch.java +++ /dev/null @@ -1,92 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.session; - -import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEventListener; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; - -import java.time.Instant; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.TimeUnit; - -/** - * @author lin - */ -@Component -public class RecordDataCatch { - - public static Map data = new ConcurrentHashMap<>(); - - @Autowired - private DeferredResultHolder deferredResultHolder; - @Autowired - private RecordEndEventListener recordEndEventListener; - - - public int put(String deviceId,String channelId, String sn, int sumNum, List recordItems) { - String key = deviceId + sn; - RecordInfo recordInfo = data.get(key); - if (recordInfo == null) { - recordInfo = new RecordInfo(); - recordInfo.setDeviceId(deviceId); - recordInfo.setChannelId(channelId); - recordInfo.setSn(sn.trim()); - recordInfo.setSumNum(sumNum); - recordInfo.setRecordList(Collections.synchronizedList(new ArrayList<>())); - recordInfo.setLastTime(Instant.now()); - recordInfo.getRecordList().addAll(recordItems); - data.put(key, recordInfo); - }else { - // 同一个设备的通道同步请求只考虑一个,其他的直接忽略 - if (!Objects.equals(sn.trim(), recordInfo.getSn())) { - return 0; - } - recordInfo.getRecordList().addAll(recordItems); - recordInfo.setLastTime(Instant.now()); - } - return recordInfo.getRecordList().size(); - } - - @Scheduled(fixedRate = 5 * 1000) //每5秒执行一次, 发现数据5秒未更新则移除数据并认为数据接收超时 - private void timerTask(){ - Set keys = data.keySet(); - // 获取五秒前的时刻 - Instant instantBefore5S = Instant.now().minusMillis(TimeUnit.SECONDS.toMillis(5)); - for (String key : keys) { - RecordInfo recordInfo = data.get(key); - // 超过五秒收不到消息任务超时, 只更新这一部分数据 - if ( recordInfo.getLastTime().isBefore(instantBefore5S)) { - // 处理录像数据, 返回给前端 - String msgKey = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + recordInfo.getDeviceId() + recordInfo.getSn(); - - // 对数据进行排序 - Collections.sort(recordInfo.getRecordList()); - - RequestMessage msg = new RequestMessage(); - msg.setKey(msgKey); - msg.setData(recordInfo); - deferredResultHolder.invokeAllResult(msg); - recordEndEventListener.delEndEventHandler(recordInfo.getDeviceId(),recordInfo.getChannelId()); - data.remove(key); - } - } - } - - public boolean isComplete(String deviceId, String sn) { - RecordInfo recordInfo = data.get(deviceId + sn); - return recordInfo != null && recordInfo.getRecordList().size() == recordInfo.getSumNum(); - } - - public RecordInfo getRecordInfo(String deviceId, String sn) { - return data.get(deviceId + sn); - } - - public void remove(String deviceId, String sn) { - data.remove(deviceId + sn); - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SipInviteSessionManager.java b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SipInviteSessionManager.java index 3a3bdaef3..a4468d921 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/session/SipInviteSessionManager.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/session/SipInviteSessionManager.java @@ -27,15 +27,15 @@ public class SipInviteSessionManager { */ public void put(SsrcTransaction ssrcTransaction){ redisTemplate.opsForHash().put(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId() - , ssrcTransaction.getStream(), ssrcTransaction); + , ssrcTransaction.getApp() + ssrcTransaction.getStream(), ssrcTransaction); redisTemplate.opsForHash().put(VideoManagerConstants.SIP_INVITE_SESSION_CALL_ID + userSetting.getServerId() , ssrcTransaction.getCallId(), ssrcTransaction); } - public SsrcTransaction getSsrcTransactionByStream(String stream){ + public SsrcTransaction getSsrcTransactionByStream(String app, String stream){ String key = VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(); - return (SsrcTransaction)redisTemplate.opsForHash().get(key, stream); + return (SsrcTransaction)redisTemplate.opsForHash().get(key, app + stream); } public SsrcTransaction getSsrcTransactionByCallId(String callId){ @@ -56,12 +56,12 @@ public class SipInviteSessionManager { return result; } - public void removeByStream(String stream) { - SsrcTransaction ssrcTransaction = getSsrcTransactionByStream(stream); + public void removeByStream(String app, String stream) { + SsrcTransaction ssrcTransaction = getSsrcTransactionByStream(app, stream); if (ssrcTransaction == null ) { return; } - redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), stream); + redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), app + stream); if (ssrcTransaction.getCallId() != null) { redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_CALL_ID + userSetting.getServerId(), ssrcTransaction.getCallId()); } @@ -74,7 +74,7 @@ public class SipInviteSessionManager { } redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_CALL_ID + userSetting.getServerId(), callId); if (ssrcTransaction.getStream() != null) { - redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), ssrcTransaction.getStream()); + redisTemplate.opsForHash().delete(VideoManagerConstants.SIP_INVITE_SESSION_STREAM + userSetting.getServerId(), ssrcTransaction.getApp() + ssrcTransaction.getStream()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java b/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java index 102f9d0c9..56a649bc5 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/task/SipRunner.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.task; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; @@ -60,9 +61,12 @@ public class SipRunner implements CommandLineRunner { @Autowired private ISendRtpServerService sendRtpServerService; + @Autowired + private UserSetting userSetting; + @Override public void run(String... args) throws Exception { - List deviceList = deviceService.getAllOnlineDevice(); + List deviceList = deviceService.getAllOnlineDevice(userSetting.getServerId()); for (Device device : deviceList) { if (deviceService.expire(device)){ @@ -86,7 +90,8 @@ public class SipRunner implements CommandLineRunner { deviceMapInDb.put(device.getDeviceId(), device); }); devicesInRedis.parallelStream().forEach(device -> { - if (deviceMapInDb.get(device.getDeviceId()) == null) { + if (deviceMapInDb.get(device.getDeviceId()) == null + && userSetting.getServerId().equals(device.getServerId())) { redisCatchStorage.removeDevice(device.getDeviceId()); } }); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java index efc1d91d3..b7892dbd3 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java @@ -5,7 +5,6 @@ import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.event.sip.SipEvent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor; import com.genersoft.iot.vmp.gb28181.transmit.event.response.ISIPResponseProcessor; -import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor; import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; @@ -13,6 +12,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import javax.sip.*; +import javax.sip.header.CSeqHeader; import javax.sip.header.CallIdHeader; import javax.sip.message.Response; import java.util.Map; @@ -27,9 +27,8 @@ import java.util.concurrent.ConcurrentHashMap; @Component public class SIPProcessorObserver implements ISIPProcessorObserver { - private static Map requestProcessorMap = new ConcurrentHashMap<>(); - private static Map responseProcessorMap = new ConcurrentHashMap<>(); - private static ITimeoutProcessor timeoutProcessor; + private static final Map requestProcessorMap = new ConcurrentHashMap<>(); + private static final Map responseProcessorMap = new ConcurrentHashMap<>(); @Autowired private SipSubscribe sipSubscribe; @@ -55,14 +54,6 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { responseProcessorMap.put(method, processor); } - /** - * 添加 超时事件订阅 - * @param processor 处理程序 - */ - public void addTimeoutProcessor(ITimeoutProcessor processor) { - timeoutProcessor = processor; - } - /** * 分发RequestEvent事件 * @param requestEvent RequestEvent事件 @@ -95,14 +86,15 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { if (((status >= Response.OK) && (status < Response.MULTIPLE_CHOICES)) || status == Response.UNAUTHORIZED) { if (status != Response.UNAUTHORIZED && responseEvent.getResponse() != null && !sipSubscribe.isEmpty() ) { CallIdHeader callIdHeader = response.getCallIdHeader(); + CSeqHeader cSeqHeader = response.getCSeqHeader(); if (callIdHeader != null) { - SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId()); + SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); if (sipEvent != null) { if (sipEvent.getOkEvent() != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult<>(responseEvent); sipEvent.getOkEvent().response(eventResult); } - sipSubscribe.removeSubscribe(callIdHeader.getCallId()); + sipSubscribe.removeSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); } } } @@ -117,15 +109,16 @@ public class SIPProcessorObserver implements ISIPProcessorObserver { } else { log.warn("接收到失败的response响应!status:" + status + ",message:" + response.getReasonPhrase()); if (responseEvent.getResponse() != null && !sipSubscribe.isEmpty() ) { - CallIdHeader callIdHeader = (CallIdHeader)responseEvent.getResponse().getHeader(CallIdHeader.NAME); + CallIdHeader callIdHeader = response.getCallIdHeader(); + CSeqHeader cSeqHeader = response.getCSeqHeader(); if (callIdHeader != null) { - SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId()); + SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); if (sipEvent != null ) { if (sipEvent.getErrorEvent() != null) { SipSubscribe.EventResult eventResult = new SipSubscribe.EventResult<>(responseEvent); sipEvent.getErrorEvent().response(eventResult); } - sipSubscribe.removeSubscribe(callIdHeader.getCallId()); + sipSubscribe.removeSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java index fcda7a720..ba2a04432 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPSender.java @@ -13,6 +13,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import javax.sip.SipException; +import javax.sip.header.CSeqHeader; import javax.sip.header.CallIdHeader; import javax.sip.header.UserAgentHeader; import javax.sip.header.ViaHeader; @@ -71,18 +72,20 @@ public class SIPSender { if (okEvent != null || errorEvent != null) { CallIdHeader callIdHeader = (CallIdHeader) message.getHeader(CallIdHeader.NAME); - SipEvent sipEvent = SipEvent.getInstance(callIdHeader.getCallId(), eventResult -> { - sipSubscribe.removeSubscribe(callIdHeader.getCallId()); + CSeqHeader cSeqHeader = (CSeqHeader) message.getHeader(CSeqHeader.NAME); + String key = callIdHeader.getCallId() + cSeqHeader.getSeqNumber(); + SipEvent sipEvent = SipEvent.getInstance(key, eventResult -> { + sipSubscribe.removeSubscribe(key); if(okEvent != null) { okEvent.response(eventResult); } }, (eventResult -> { - sipSubscribe.removeSubscribe(callIdHeader.getCallId()); + sipSubscribe.removeSubscribe(key); if (errorEvent != null) { errorEvent.response(eventResult); } }), timeout == null ? sipConfig.getTimeout() : timeout); - sipSubscribe.addSubscribe(callIdHeader.getCallId(), sipEvent); + sipSubscribe.addSubscribe(key, sipEvent); } if ("TCP".equals(transport)) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java index 61aaac4a0..d39ce28e5 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/callback/DeferredResultHolder.java @@ -18,20 +18,6 @@ import java.util.concurrent.ConcurrentHashMap; @SuppressWarnings(value = {"rawtypes", "unchecked"}) @Component public class DeferredResultHolder { - - public static final String CALLBACK_CMD_DEVICESTATUS = "CALLBACK_DEVICESTATUS"; - - public static final String CALLBACK_CMD_DEVICEINFO = "CALLBACK_DEVICEINFO"; - - public static final String CALLBACK_CMD_DEVICECONTROL = "CALLBACK_DEVICECONTROL"; - - public static final String CALLBACK_CMD_DEVICECONFIG = "CALLBACK_DEVICECONFIG"; - - public static final String CALLBACK_CMD_CONFIGDOWNLOAD = "CALLBACK_CONFIGDOWNLOAD"; - - public static final String CALLBACK_CMD_CATALOG = "CALLBACK_CATALOG"; - - public static final String CALLBACK_CMD_RECORDINFO = "CALLBACK_RECORDINFO"; public static final String CALLBACK_CMD_PLAY = "CALLBACK_PLAY"; @@ -39,20 +25,11 @@ public class DeferredResultHolder { public static final String CALLBACK_CMD_DOWNLOAD = "CALLBACK_DOWNLOAD"; - public static final String CALLBACK_CMD_PROXY = "CALLBACK_PROXY"; - - public static final String CALLBACK_CMD_STOP = "CALLBACK_STOP"; public static final String UPLOAD_FILE_CHANNEL = "UPLOAD_FILE_CHANNEL"; public static final String CALLBACK_CMD_MOBILE_POSITION = "CALLBACK_CMD_MOBILE_POSITION"; - public static final String CALLBACK_CMD_PRESETQUERY = "CALLBACK_PRESETQUERY"; - - public static final String CALLBACK_CMD_ALARM = "CALLBACK_ALARM"; - - public static final String CALLBACK_CMD_BROADCAST = "CALLBACK_BROADCAST"; - public static final String CALLBACK_CMD_SNAP= "CALLBACK_SNAP"; private Map> map = new ConcurrentHashMap<>(); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java index dca16ba84..784a73c64 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommander.java @@ -9,6 +9,7 @@ import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import gov.nist.javax.sip.message.SIPRequest; @@ -23,45 +24,6 @@ import java.text.ParseException; */ public interface ISIPCommander { - /** - * 云台方向放控制,使用配置文件中的默认镜头移动速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - */ - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台方向放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param moveSpeed 镜头移动速度 - */ - void ptzdirectCmd(Device device,String channelId,int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - void ptzZoomCmd(Device device,String channelId,int inOut) throws InvalidArgumentException, ParseException, SipException; - - /** - * 云台缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - void ptzZoomCmd(Device device,String channelId,int inOut, int moveSpeed) throws InvalidArgumentException, ParseException, SipException; - /** * 云台控制,支持方向与缩放控制 * @@ -129,13 +91,10 @@ public interface ISIPCommander { /** * 视频流停止 */ - void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; + void streamByeCmd(Device device, String channelId, String app, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; void talkStreamCmd(MediaServer mediaServerItem, SendRtpInfo sendRtpItem, Device device, DeviceChannel channelId, String callId, HookSubscribe.Event event, HookSubscribe.Event eventForPush, SipSubscribe.Event okEvent, SipSubscribe.Event errorEvent, Long timeout) throws InvalidArgumentException, SipException, ParseException; - - void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException; - void streamByeCmd(Device device, String channelId, SipTransactionInfo sipTransactionInfo, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; /** @@ -184,7 +143,7 @@ public interface ISIPCommander { * @param channelId 预览通道 * @param recordCmdStr 录像命令:Record / StopRecord */ - void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void recordCmd(Device device, String channelId, String recordCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 远程启动控制命令 @@ -198,7 +157,7 @@ public interface ISIPCommander { * * @param device 视频设备 */ - void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void guardCmd(Device device, String guardCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 报警复位命令 @@ -207,7 +166,7 @@ public interface ISIPCommander { * @param alarmMethod 报警方式(可选) * @param alarmType 报警类型(可选) */ - void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void alarmResetCmd(Device device, String alarmMethod, String alarmType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 强制关键帧命令,设备收到此命令应立刻发送一个IDR帧 @@ -221,7 +180,7 @@ public interface ISIPCommander { * 看守位控制命令 * */ - void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException; + void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 设备配置命令 @@ -232,30 +191,24 @@ public interface ISIPCommander { /** * 设备配置命令:basicParam - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param name 设备/通道名称(可选) - * @param expiration 注册过期时间(可选) - * @param heartBeatInterval 心跳间隔时间(可选) - * @param heartBeatCount 心跳超时次数(可选) - */ - void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + */ + void deviceBasicConfigCmd(Device device, BasicParam basicParam, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备状态 * * @param device 视频设备 */ - void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + void deviceStatusQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备信息 - * - * @param device 视频设备 - * @return + * + * @param device 视频设备 + * @param callback + * @return */ - void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException; + void deviceInfoQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询目录列表 @@ -287,7 +240,7 @@ public interface ISIPCommander { * @return true = 命令发送成功 */ void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, - String alarmType, String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + String alarmType, String startTime, String endTime, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备配置 @@ -296,14 +249,14 @@ public interface ISIPCommander { * @param channelId 通道编码(可选) * @param configType 配置类型: */ - void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询设备预置位置 * * @param device 视频设备 */ - void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException; + void presetQuery(Device device, String channelId, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; /** * 查询移动设备位置数据 @@ -326,7 +279,6 @@ public interface ISIPCommander { * @param expires 订阅过期时间(0 = 取消订阅) * @param startPriority 报警起始级别(可选) * @param endPriority 报警终止级别(可选) - * @param alarmType 报警类型 * @param startTime 报警发生起始时间(可选) * @param endTime 报警发生终止时间(可选) * @return true = 命令发送成功 @@ -347,7 +299,7 @@ public interface ISIPCommander { * @param channelId 通道id * @param cmdString 前端控制指令串 */ - void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException; + void dragZoomCmd(Device device, String channelId, String cmdString, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException; void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java index 6a80dd3ac..c94a072f0 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/ISIPCommanderForPlatform.java @@ -144,7 +144,7 @@ public interface ISIPCommanderForPlatform { void streamByeCmd(Platform platform, SendRtpInfo sendRtpItem, CommonGBChannel channel) throws SipException, InvalidArgumentException, ParseException; - void streamByeCmd(Platform platform, CommonGBChannel channel, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; + void streamByeCmd(Platform platform, CommonGBChannel channel, String app, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException; void broadcastInviteCmd(Platform platform, CommonGBChannel channel, String sourceId, MediaServer mediaServerItem, SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent, diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java index 9e5fb182b..8e607ecc2 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommander.java @@ -7,7 +7,9 @@ import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.SipLayer; import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.MessageSubscribe; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; +import com.genersoft.iot.vmp.gb28181.event.sip.MessageEvent; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; import com.genersoft.iot.vmp.gb28181.transmit.cmd.ISIPCommander; @@ -19,8 +21,10 @@ import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.service.IMediaServerService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.service.bean.SSRCInfo; import com.genersoft.iot.vmp.utils.DateUtil; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import gov.nist.javax.sip.message.SIPRequest; import gov.nist.javax.sip.message.SIPResponse; import lombok.extern.slf4j.Slf4j; @@ -71,59 +75,8 @@ public class SIPCommander implements ISIPCommander { @Autowired private IMediaServerService mediaServerService; - - - /** - * 云台方向放控制,使用配置文件中的默认镜头移动速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - */ - @Override - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, leftRight, upDown, 0, sipConfig.getPtzSpeed(), 0); - } - - /** - * 云台方向放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param leftRight 镜头左移右移 0:停止 1:左移 2:右移 - * @param upDown 镜头上移下移 0:停止 1:上移 2:下移 - * @param moveSpeed 镜头移动速度 - */ - @Override - public void ptzdirectCmd(Device device, String channelId, int leftRight, int upDown, int moveSpeed) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, leftRight, upDown, 0, moveSpeed, 0); - } - - /** - * 云台缩放控制,使用配置文件中的默认镜头缩放速度 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - */ - @Override - public void ptzZoomCmd(Device device, String channelId, int inOut) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, 0, 0, inOut, 0, sipConfig.getPtzSpeed()); - } - - /** - * 云台缩放控制 - * - * @param device 控制设备 - * @param channelId 预览通道 - * @param inOut 镜头放大缩小 0:停止 1:缩小 2:放大 - * @param zoomSpeed 镜头缩放速度 - */ - @Override - public void ptzZoomCmd(Device device, String channelId, int inOut, int zoomSpeed) throws InvalidArgumentException, ParseException, SipException { - ptzCmd(device, channelId, 0, 0, inOut, 0, zoomSpeed); - } + @Autowired + private MessageSubscribe messageSubscribe; /** * 云台指令码计算 @@ -211,9 +164,6 @@ public class SIPCommander implements ISIPCommander { ptzXml.append("\r\n"); ptzXml.append("\r\n"); - - - SIPRequest request = (SIPRequest) headerProvider.createMessageRequest(device, ptzXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); @@ -332,14 +282,15 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, ssrcInfo.getSsrc(),sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); errorEvent.response(e); }), e -> { ResponseEvent responseEvent = (ResponseEvent) e.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); String callId = response.getCallIdHeader().getCallId(); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), callId, stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), + callId,ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAY); sessionManager.put(ssrcTransaction); okEvent.response(e); @@ -435,7 +386,9 @@ public class SIPCommander implements ISIPCommander { ResponseEvent responseEvent = (ResponseEvent) event.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), - channel.getId(), sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport()).getCallId(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); + channel.getId(), sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()), + device.getTransport()).getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrcInfo.getSsrc(), + mediaServerItem.getId(), response, InviteSessionType.PLAYBACK); sessionManager.put(ssrcTransaction); okEvent.response(event); }, timeout); @@ -526,7 +479,9 @@ public class SIPCommander implements ISIPCommander { SIPResponse response = (SIPResponse) responseEvent.getResponse(); String contentString =new String(response.getRawContent()); String ssrc = SipUtils.getSsrcFromSdp(contentString); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), response.getCallIdHeader().getCallId(), ssrcInfo.getStream(), ssrc, mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), + response.getCallIdHeader().getCallId(), ssrcInfo.getApp(), ssrcInfo.getStream(), ssrc, + mediaServerItem.getId(), response, InviteSessionType.DOWNLOAD); sessionManager.put(ssrcTransaction); okEvent.response(event); }, timeout); @@ -586,32 +541,24 @@ public class SIPCommander implements ISIPCommander { Request request = headerProvider.createInviteRequest(device, channel.getDeviceId(), content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null, sendRtpItem.getSsrc(), callIdHeader); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, (e -> { - sessionManager.removeByStream(sendRtpItem.getStream()); + sessionManager.removeByStream(sendRtpItem.getApp(), sendRtpItem.getStream()); mediaServerService.releaseSsrc(mediaServerItem.getId(), sendRtpItem.getSsrc()); errorEvent.response(e); }), e -> { // 这里为例避免一个通道的点播只有一个callID这个参数使用一个固定值 ResponseEvent responseEvent = (ResponseEvent) e.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), "talk", stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK); + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), channel.getId(), "talk",sendRtpItem.getApp(), stream, sendRtpItem.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.TALK); sessionManager.put(ssrcTransaction); okEvent.response(e); }, timeout); } - /** - * 视频流停止, 不使用回调 - */ - @Override - public void streamByeCmd(Device device, String channelId, String stream, String callId) throws InvalidArgumentException, ParseException, SipException, SsrcTransactionNotFoundException { - streamByeCmd(device, channelId, stream, callId, null); - } - /** * 视频流停止 */ @Override - public void streamByeCmd(Device device, String channelId, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { + public void streamByeCmd(Device device, String channelId, String app, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { if (device == null) { log.warn("[发送BYE] device为null"); return; @@ -620,7 +567,7 @@ public class SIPCommander implements ISIPCommander { if (callId != null) { ssrcTransaction = sessionManager.getSsrcTransactionByCallId(callId); }else if (stream != null) { - ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream); + ssrcTransaction = sessionManager.getSsrcTransactionByStream(app, stream); } if (ssrcTransaction == null) { @@ -677,13 +624,16 @@ public class SIPCommander implements ISIPCommander { * @param recordCmdStr 录像命令:Record / StopRecord */ @Override - public void recordCmd(Device device, String channelId, String recordCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + public void recordCmd(Device device, String channelId, String recordCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + final String cmdType = "DeviceControl"; + final int sn = (int) ((Math.random() * 9 + 1) * 100000); + StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); if (ObjectUtils.isEmpty(channelId)) { cmdXml.append("" + device.getDeviceId() + "\r\n"); } else { @@ -692,10 +642,14 @@ public class SIPCommander implements ISIPCommander { cmdXml.append("" + recordCmdStr + "\r\n"); cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + },null); } /** @@ -729,22 +683,29 @@ public class SIPCommander implements ISIPCommander { * @param guardCmdStr "SetGuard"/"ResetGuard" */ @Override - public void guardCmd(Device device, String guardCmdStr, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + public void guardCmd(Device device, String guardCmdStr, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceControl"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); cmdXml.append("" + device.getDeviceId() + "\r\n"); cmdXml.append("" + guardCmdStr + "\r\n"); cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", device.getDeviceId(), 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -753,14 +714,17 @@ public class SIPCommander implements ISIPCommander { * @param device 视频设备 */ @Override - public void alarmCmd(Device device, String alarmMethod, String alarmType, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + public void alarmResetCmd(Device device, String alarmMethod, String alarmType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceControl"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); cmdXml.append("" + device.getDeviceId() + "\r\n"); cmdXml.append("ResetAlarm\r\n"); if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) { @@ -777,10 +741,14 @@ public class SIPCommander implements ISIPCommander { } cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", device.getDeviceId(), 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -822,19 +790,21 @@ public class SIPCommander implements ISIPCommander { * @param presetIndex 调用预置位编号,开启看守位时使用,取值范围0~255 */ @Override - public void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, SipSubscribe.Event errorEvent,SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException { + public void homePositionCmd(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceControl"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("DeviceControl\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); + channelId = device.getDeviceId(); } + cmdXml.append("" + channelId + "\r\n"); cmdXml.append("\r\n"); if (enabled) { cmdXml.append("1\r\n"); @@ -846,10 +816,14 @@ public class SIPCommander implements ISIPCommander { cmdXml.append("\r\n"); cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent,okEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -864,55 +838,50 @@ public class SIPCommander implements ISIPCommander { /** * 设备配置命令:basicParam - * - * @param device 视频设备 - * @param channelId 通道编码(可选) - * @param name 设备/通道名称(可选) - * @param expiration 注册过期时间(可选) - * @param heartBeatInterval 心跳间隔时间(可选) - * @param heartBeatCount 心跳超时次数(可选) */ @Override - public void deviceBasicConfigCmd(Device device, String channelId, String name, String expiration, - String heartBeatInterval, String heartBeatCount, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public void deviceBasicConfigCmd(Device device, BasicParam basicParam, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + int sn = (int) ((Math.random() * 9 + 1) * 100000); + String cmdType = "DeviceConfig"; StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("DeviceConfig\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); + String channelId = basicParam.getChannelId(); if (ObjectUtils.isEmpty(channelId)) { - cmdXml.append("" + device.getDeviceId() + "\r\n"); - } else { - cmdXml.append("" + channelId + "\r\n"); + channelId = device.getDeviceId(); } + cmdXml.append("" + channelId + "\r\n"); cmdXml.append("\r\n"); - if (!ObjectUtils.isEmpty(name)) { - cmdXml.append("" + name + "\r\n"); + if (!ObjectUtils.isEmpty(basicParam.getName())) { + cmdXml.append("" + basicParam.getName() + "\r\n"); } - if (NumericUtil.isInteger(expiration)) { - if (Integer.valueOf(expiration) > 0) { - cmdXml.append("" + expiration + "\r\n"); + if (NumericUtil.isInteger(basicParam.getExpiration())) { + if (Integer.parseInt(basicParam.getExpiration()) > 0) { + cmdXml.append("" + basicParam.getExpiration() + "\r\n"); } } - if (NumericUtil.isInteger(heartBeatInterval)) { - if (Integer.valueOf(heartBeatInterval) > 0) { - cmdXml.append("" + heartBeatInterval + "\r\n"); - } + if (basicParam.getHeartBeatInterval() != null && basicParam.getHeartBeatInterval() > 0) { + cmdXml.append("" + basicParam.getHeartBeatInterval() + "\r\n"); } - if (NumericUtil.isInteger(heartBeatCount)) { - if (Integer.valueOf(heartBeatCount) > 0) { - cmdXml.append("" + heartBeatCount + "\r\n"); - } + if (basicParam.getHeartBeatCount() != null && basicParam.getHeartBeatCount() > 0) { + cmdXml.append("" + basicParam.getHeartBeatCount() + "\r\n"); } cmdXml.append("\r\n"); cmdXml.append("\r\n"); + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -921,46 +890,63 @@ public class SIPCommander implements ISIPCommander { * @param device 视频设备 */ @Override - public void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public void deviceStatusQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceStatus"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); String charset = device.getCharset(); StringBuffer catalogXml = new StringBuffer(200); catalogXml.append("\r\n"); catalogXml.append("\r\n"); - catalogXml.append("DeviceStatus\r\n"); - catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + cmdType + "\r\n"); + catalogXml.append("" + sn + "\r\n"); catalogXml.append("" + device.getDeviceId() + "\r\n"); catalogXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", device.getDeviceId(), 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** * 查询设备信息 * - * @param device 视频设备 + * @param device 视频设备 + * @param callback */ @Override - public void deviceInfoQuery(Device device) throws InvalidArgumentException, SipException, ParseException { + public void deviceInfoQuery(Device device, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceInfo"; + String sn = (int) ((Math.random() * 9 + 1) * 100000) + ""; StringBuffer catalogXml = new StringBuffer(200); String charset = device.getCharset(); catalogXml.append("\r\n"); catalogXml.append("\r\n"); - catalogXml.append("DeviceInfo\r\n"); - catalogXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + catalogXml.append("" + cmdType +"\r\n"); + catalogXml.append("" + sn + "\r\n"); catalogXml.append("" + device.getDeviceId() + "\r\n"); catalogXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn, device.getDeviceId(), 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, catalogXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + if (callback != null) { + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + } + }); } @@ -1046,14 +1032,17 @@ public class SIPCommander implements ISIPCommander { */ @Override public void alarmInfoQuery(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, - String startTime, String endTime, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + String startTime, String endTime, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "Alarm"; + String sn = (int) ((Math.random() * 9 + 1) * 100000) + ""; StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("Alarm\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); cmdXml.append("" + device.getDeviceId() + "\r\n"); if (!ObjectUtils.isEmpty(startPriority)) { cmdXml.append("" + startPriority + "\r\n"); @@ -1075,10 +1064,14 @@ public class SIPCommander implements ISIPCommander { } cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn, device.getDeviceId(), 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -1089,14 +1082,16 @@ public class SIPCommander implements ISIPCommander { * @param configType 配置类型: */ @Override - public void deviceConfigQuery(Device device, String channelId, String configType, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + String cmdType = "ConfigDownload"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("ConfigDownload\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); if (ObjectUtils.isEmpty(channelId)) { cmdXml.append("" + device.getDeviceId() + "\r\n"); } else { @@ -1105,10 +1100,16 @@ public class SIPCommander implements ISIPCommander { cmdXml.append("" + configType + "\r\n"); cmdXml.append("\r\n"); - + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + if (callback != null) { + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + } + }); } /** @@ -1117,14 +1118,17 @@ public class SIPCommander implements ISIPCommander { * @param device 视频设备 */ @Override - public void presetQuery(Device device, String channelId, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException { + public void presetQuery(Device device, String channelId, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "PresetQuery"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer cmdXml = new StringBuffer(200); String charset = device.getCharset(); cmdXml.append("\r\n"); cmdXml.append("\r\n"); - cmdXml.append("PresetQuery\r\n"); - cmdXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + cmdXml.append("" + cmdType + "\r\n"); + cmdXml.append("" + sn + "\r\n"); if (ObjectUtils.isEmpty(channelId)) { cmdXml.append("" + device.getDeviceId() + "\r\n"); } else { @@ -1132,9 +1136,14 @@ public class SIPCommander implements ISIPCommander { } cmdXml.append("\r\n"); + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); Request request = headerProvider.createMessageRequest(device, cmdXml.toString(), null, SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, errorEvent); + sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()), request, eventResult -> { + messageSubscribe.removeSubscribe(messageEvent.getKey()); + callback.run(ErrorCode.ERROR100.getCode(), "失败," + eventResult.msg, null); + }); } /** @@ -1273,14 +1282,17 @@ public class SIPCommander implements ISIPCommander { } @Override - public void dragZoomCmd(Device device, String channelId, String cmdString) throws InvalidArgumentException, SipException, ParseException { + public void dragZoomCmd(Device device, String channelId, String cmdString, ErrorCallback callback) throws InvalidArgumentException, SipException, ParseException { + + String cmdType = "DeviceControl"; + int sn = (int) ((Math.random() * 9 + 1) * 100000); StringBuffer dragXml = new StringBuffer(200); String charset = device.getCharset(); dragXml.append("\r\n"); dragXml.append("\r\n"); - dragXml.append("DeviceControl\r\n"); - dragXml.append("" + (int) ((Math.random() * 9 + 1) * 100000) + "\r\n"); + dragXml.append("" + cmdType + "\r\n"); + dragXml.append("" + sn + "\r\n"); if (ObjectUtils.isEmpty(channelId)) { dragXml.append("" + device.getDeviceId() + "\r\n"); } else { @@ -1289,8 +1301,10 @@ public class SIPCommander implements ISIPCommander { dragXml.append(cmdString); dragXml.append("\r\n"); + MessageEvent messageEvent = MessageEvent.getInstance(cmdType, sn + "", channelId, 1000L, callback); + messageSubscribe.addSubscribe(messageEvent); + Request request = headerProvider.createMessageRequest(device, dragXml.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), null,sipSender.getNewCallIdHeader(sipLayer.getLocalIp(device.getLocalIp()),device.getTransport())); - log.debug("拉框信令: " + request.toString()); sipSender.transmitRequest(sipLayer.getLocalIp(device.getLocalIp()),request); } @@ -1362,7 +1376,7 @@ public class SIPCommander implements ISIPCommander { @Override public void playbackControlCmd(Device device, DeviceChannel channel, String stream, String content, SipSubscribe.Event errorEvent, SipSubscribe.Event okEvent) throws SipException, InvalidArgumentException, ParseException { - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream("rtp", stream); if (ssrcTransaction == null) { log.info("[回放控制]未找到视频流信息,设备:{}, 流ID: {}", device.getDeviceId(), stream); return; diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java index 2dbfdf192..5e5a207b6 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/impl/SIPCommanderForPlatform.java @@ -7,7 +7,6 @@ import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException; import com.genersoft.iot.vmp.gb28181.SipLayer; import com.genersoft.iot.vmp.gb28181.bean.*; -import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.session.SipInviteSessionManager; import com.genersoft.iot.vmp.gb28181.transmit.SIPSender; @@ -644,13 +643,13 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { } @Override - public void streamByeCmd(Platform platform, CommonGBChannel channel, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { + public void streamByeCmd(Platform platform, CommonGBChannel channel, String app, String stream, String callId, SipSubscribe.Event okEvent) throws InvalidArgumentException, SipException, ParseException, SsrcTransactionNotFoundException { SsrcTransaction ssrcTransaction = null; if (callId != null) { ssrcTransaction = sessionManager.getSsrcTransactionByCallId(callId); }else if (stream != null) { - ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream); + ssrcTransaction = sessionManager.getSsrcTransactionByStream(app, stream); } if (ssrcTransaction == null) { throw new SsrcTransactionNotFoundException(platform.getServerGBId(), channel.getGbDeviceId(), callId, stream); @@ -658,7 +657,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { mediaServerService.releaseSsrc(ssrcTransaction.getMediaServerId(), ssrcTransaction.getSsrc()); mediaServerService.closeRTPServer(ssrcTransaction.getMediaServerId(), ssrcTransaction.getStream()); - sessionManager.removeByStream(ssrcTransaction.getStream()); + sessionManager.removeByStream(ssrcTransaction.getApp(), ssrcTransaction.getStream()); Request byteRequest = headerProviderPlatformProvider.createByteRequest(platform, channel.getGbDeviceId(), ssrcTransaction.getSipTransactionInfo()); sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), byteRequest, null, okEvent); @@ -743,14 +742,15 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform { content.toString(), SipUtils.getNewViaTag(), SipUtils.getNewFromTag(), ssrcInfo.getSsrc(), callIdHeader); sipSender.transmitRequest(sipLayer.getLocalIp(platform.getDeviceIp()), request, (e -> { - sessionManager.removeByStream(ssrcInfo.getStream()); + sessionManager.removeByStream(ssrcInfo.getApp(), ssrcInfo.getStream()); mediaServerService.releaseSsrc(mediaServerItem.getId(), ssrcInfo.getSsrc()); subscribe.removeSubscribe(hook); errorEvent.response(e); }), e -> { ResponseEvent responseEvent = (ResponseEvent) e.event; SIPResponse response = (SIPResponse) responseEvent.getResponse(); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(), callIdHeader.getCallId(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST); + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForPlatform(platform.getServerGBId(), channel.getGbId(), + callIdHeader.getCallId(), ssrcInfo.getApp(), stream, ssrcInfo.getSsrc(), mediaServerItem.getId(), response, InviteSessionType.BROADCAST); sessionManager.put(ssrcTransaction); okEvent.response(e); }); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java index c51b570a0..26a886b78 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/ByeRequestProcessor.java @@ -169,7 +169,7 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In } try { log.info("[停止点播] {}/{}", sendRtpItem.getTargetId(), sendRtpItem.getChannelId()); - cmder.streamByeCmd(device, deviceChannel.getDeviceId(), streamId, null); + cmder.streamByeCmd(device, deviceChannel.getDeviceId(), sendRtpItem.getApp(), sendRtpItem.getStream(), null, null); } catch (InvalidArgumentException | ParseException | SipException | SsrcTransactionNotFoundException e) { log.error("[收到bye] {} 无其它观看者,通知设备停止推流, 发送BYE失败 {}",streamId, e.getMessage()); @@ -196,10 +196,10 @@ public class ByeRequestProcessor extends SIPRequestProcessorParent implements In return; } String mediaServerId = ssrcTransaction.getMediaServerId(); - platformService.stopBroadcast(platform, channel, ssrcTransaction.getStream(), false, + platformService.stopBroadcast(platform, channel, ssrcTransaction.getApp(), ssrcTransaction.getStream(), false, mediaServerService.getOne(mediaServerId)); DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); playService.stopAudioBroadcast(device, deviceChannel); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java index 75a8dcd43..4ddbc22be 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/InviteRequestProcessor.java @@ -121,7 +121,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements SIPRequest request = (SIPRequest)evt.getRequest(); try { - InviteInfo inviteInfo = decode(evt); + InviteMessageInfo inviteInfo = decode(evt); // 查询请求是否来自上级平台\设备 Platform platform = platformService.queryPlatformByServerGBId(inviteInfo.getRequesterId()); @@ -247,9 +247,9 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } } - private InviteInfo decode(RequestEvent evt) throws SdpException { + private InviteMessageInfo decode(RequestEvent evt) throws SdpException { - InviteInfo inviteInfo = new InviteInfo(); + InviteMessageInfo inviteInfo = new InviteMessageInfo(); SIPRequest request = (SIPRequest)evt.getRequest(); String[] channelIdArrayFromSub = SipUtils.getChannelIdFromRequest(request); @@ -349,7 +349,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } - private String createSendSdp(SendRtpInfo sendRtpItem, InviteInfo inviteInfo, String sdpIp) { + private String createSendSdp(SendRtpInfo sendRtpItem, InviteMessageInfo inviteInfo, String sdpIp) { StringBuilder content = new StringBuilder(200); content.append("v=0\r\n"); content.append("o=" + inviteInfo.getTargetChannelId() + " 0 0 IN IP4 " + sdpIp + "\r\n"); @@ -393,7 +393,7 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements } } - public void inviteFromDeviceHandle(SIPRequest request, InviteInfo inviteInfo) { + public void inviteFromDeviceHandle(SIPRequest request, InviteMessageInfo inviteInfo) { if (inviteInfo.getSourceChannelId() == null) { log.warn("来自设备的Invite请求,无法从请求信息中确定请求来自的通道,已忽略,requesterId: {}", inviteInfo.getRequesterId()); @@ -624,7 +624,8 @@ public class InviteRequestProcessor extends SIPRequestProcessorParent implements audioBroadcastCatch.setStatus(AudioBroadcastCatchStatus.Ok); audioBroadcastCatch.setSipTransactionInfoByRequest(sipResponse); audioBroadcastManager.update(audioBroadcastCatch); - SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), sendRtpItem.getChannelId(), request.getCallIdHeader().getCallId(), sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(), sipResponse, InviteSessionType.BROADCAST); + SsrcTransaction ssrcTransaction = SsrcTransaction.buildForDevice(device.getDeviceId(), sendRtpItem.getChannelId(), + request.getCallIdHeader().getCallId(), sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc(), sendRtpItem.getMediaServerId(), sipResponse, InviteSessionType.BROADCAST); sessionManager.put(ssrcTransaction); // 开启发流,大华在收到200OK后就会开始建立连接 if (!device.isBroadcastPushAfterAck()) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java index 86be394a8..8861282f8 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/NotifyRequestForCatalogProcessor.java @@ -115,7 +115,7 @@ public class NotifyRequestForCatalogProcessor extends SIPRequestProcessorParent log.info("[解析CatalogChannelEvent]成功:但是解析通道信息失败, 原文如下: \n{}", new String(evt.getRequest().getRawContent())); continue; } - catalogChannelEvent.getChannel().setDeviceDbId(device.getId()); + catalogChannelEvent.getChannel().setDataDeviceId(device.getId()); } catch (InvocationTargetException | NoSuchMethodException | InstantiationException | IllegalAccessException e) { log.error("[解析CatalogChannelEvent]失败,", e); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java index 44a3eb1ed..85eff4105 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java @@ -166,7 +166,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen if (device == null) { device = new Device(); - device.setStreamMode("UDP"); + device.setStreamMode("TCP-PASSIVE"); device.setCharset("GB2312"); device.setGeoCoordSys("WGS84"); device.setMediaServerId("auto"); @@ -174,7 +174,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen device.setOnLine(false); } else { if (ObjectUtils.isEmpty(device.getStreamMode())) { - device.setStreamMode("UDP"); + device.setStreamMode("TCP-PASSIVE"); } if (ObjectUtils.isEmpty(device.getCharset())) { device.setCharset("GB2312"); @@ -183,7 +183,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen device.setGeoCoordSys("WGS84"); } } - + device.setServerId(userSetting.getServerId()); device.setIp(remoteAddressInfo.getIp()); device.setPort(remoteAddressInfo.getPort()); device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort()))); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java index 238cda239..8e2b42c75 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/info/InfoRequestProcessor.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.info; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.service.*; @@ -101,7 +102,7 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I return; } // 判断通道类型 - if (channel.getGbDeviceDbId() == null) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 非国标通道不支持录像回放控制 log.warn("[INFO 消息] 非国标通道不支持录像回放控制: 通道ID: {}", sendRtpInfo.getChannelId()); responseAck(request, Response.FORBIDDEN, ""); @@ -109,7 +110,7 @@ public class InfoRequestProcessor extends SIPRequestProcessorParent implements I } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", sendRtpInfo.getChannelId()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java index 237eab162..6d5caddaf 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/MessageRequestProcessor.java @@ -24,6 +24,7 @@ import org.springframework.stereotype.Component; import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; import javax.sip.SipException; +import javax.sip.header.CSeqHeader; import javax.sip.header.CallIdHeader; import javax.sip.message.Response; import java.text.ParseException; @@ -69,6 +70,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement // logger.info("接收到消息:" + evt.getRequest()); String deviceId = SipUtils.getUserIdFromFromHeader(evt.getRequest()); CallIdHeader callIdHeader = sipRequest.getCallIdHeader(); + CSeqHeader cSeqHeader = sipRequest.getCSeqHeader(); // 先从会话内查找 SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByCallId(callIdHeader.getCallId()); // 兼容海康 媒体通知 消息from字段不是设备ID的问题 @@ -94,7 +96,7 @@ public class MessageRequestProcessor extends SIPRequestProcessorParent implement // 不存在则回复404 responseAck(request, Response.NOT_FOUND, "device "+ deviceId +" not found"); log.warn("[设备未找到 ]deviceId: {}, callId: {}", deviceId, callIdHeader.getCallId()); - SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId()); + SipEvent sipEvent = sipSubscribe.getSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber()); if (sipEvent != null && sipEvent.getErrorEvent() != null){ DeviceNotFoundEvent deviceNotFoundEvent = new DeviceNotFoundEvent(evt.getDialog()); deviceNotFoundEvent.setCallId(callIdHeader.getCallId()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java index cb1cced65..8f7e036af 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/control/cmd/DeviceControlQueryMessageHandler.java @@ -1,15 +1,18 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.cmd; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.common.enums.DeviceControlType; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelControlService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; import com.genersoft.iot.vmp.gb28181.transmit.cmd.impl.SIPCommander; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.control.ControlMessageHandler; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; import org.dom4j.Element; @@ -41,6 +44,9 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent @Autowired private IGbChannelService channelService; + @Autowired + private IGbChannelControlService channelControlService; + @Autowired private IDeviceService deviceService; @@ -134,49 +140,91 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理云台指令 */ private void handlePtzCmd(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) { - if (channel.getGbDeviceDbId() == 0) { - // 只支持国标的云台控制 - log.warn("[INFO 消息] 只支持国标的云台控制, 通道ID: {}", channel.getGbId()); - try { - responseAck(request, Response.FORBIDDEN, ""); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 错误信息: {}", e.getMessage()); - } - return; - } - // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); - if (device == null) { - // 不存在则回复404 - log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); - try { - responseAck(request, Response.NOT_FOUND, "device not found"); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 错误信息: {}", e.getMessage()); - } - return; - } + if (channel.getDataType() == ChannelDataType.GB28181.value) { - DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); - if (deviceChannel == null) { - log.warn("[deviceControl] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(), - device.getDeviceId(), channel.getGbId()); - try { - responseAck(request, Response.NOT_FOUND, "channel not found"); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 错误信息: {}", e.getMessage()); + deviceChannelService.handlePtzCmd(channel.getDataDeviceId(), channel.getGbId(), rootElement, type, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + }else { + // 解析云台控制参数 + String cmdString = getText(rootElement, type.getVal()); + IFrontEndControlCode frontEndControlCode = FrontEndCode.decode(cmdString); + if (frontEndControlCode == null) { + log.info("[INFO 消息] 不支持的控制方式"); + try { + responseAck(request, Response.FORBIDDEN, ""); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + return; + } + switch (frontEndControlCode.getType()){ + case PTZ: + channelControlService.ptz(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + case FI: + channelControlService.fi(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + case PRESET: + channelControlService.preset(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + case TOUR: + channelControlService.tour(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + case SCAN: + channelControlService.scan(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + case AUXILIARY: + channelControlService.auxiliary(channel, (FrontEndControlCodeForPTZ)frontEndControlCode, ((code, msg, data) -> { + try { + responseAck(request, code, msg); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } + })); + break; + default: + log.info("[INFO 消息] 设备不支持的控制方式"); + try { + responseAck(request, Response.FORBIDDEN, ""); + } catch (InvalidArgumentException | SipException | ParseException exception) { + log.error("[命令发送失败] 云台指令: {}", exception.getMessage()); + } } - return; - } - log.info("[deviceControl] 命令: {}, 设备: {}({}), 通道{}({}", type, device.getName(), device.getDeviceId(), - deviceChannel.getName(), deviceChannel.getDeviceId()); - String cmdString = getText(rootElement, type.getVal()); - try { - cmder.fronEndCmd(device, deviceChannel.getDeviceId(), cmdString, - errorResult -> onError(request, errorResult), - okResult -> onOk(request, okResult)); - } catch (InvalidArgumentException | SipException | ParseException e) { - log.error("[命令发送失败] 云台/前端: {}", e.getMessage()); } } @@ -184,7 +232,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理强制关键帧 */ private void handleIFameCmd(CommonGBChannel channel, SIPRequest request) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的处理强制关键帧, 通道ID: {}", channel.getGbId()); try { @@ -195,7 +243,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -232,7 +280,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理重启命令 */ private void handleTeleBootCmd(CommonGBChannel channel, SIPRequest request) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的重启命令, 通道ID: {}", channel.getGbId()); try { @@ -243,7 +291,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -267,9 +315,9 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理拉框控制 */ private void handleDragZoom(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 - log.warn("[INFO 消息] 只支持国标的拉框控制, 通道ID: {}", channel.getGbId()); + log.warn("[deviceControl-DragZoom] 只支持国标的拉框控制, 通道ID: {}", channel.getGbId()); try { responseAck(request, Response.FORBIDDEN, ""); } catch (SipException | InvalidArgumentException | ParseException e) { @@ -278,10 +326,10 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 - log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); + log.warn("[deviceControl-DragZoom] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); try { responseAck(request, Response.NOT_FOUND, "device not found"); } catch (SipException | InvalidArgumentException | ParseException e) { @@ -292,7 +340,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); if (deviceChannel == null) { - log.warn("[deviceControl] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(), + log.warn("[deviceControl-DragZoom] 未找到设备原始通道, 设备: {}({}),通道编号:{}", device.getName(), device.getDeviceId(), channel.getGbId()); try { responseAck(request, Response.NOT_FOUND, "channel not found"); @@ -305,7 +353,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent deviceChannel.getName(), deviceChannel.getDeviceId()); try { DragZoomRequest dragZoomRequest = loadElement(rootElement, DragZoomRequest.class); - DragZoomRequest.DragZoom dragZoom = dragZoomRequest.getDragZoomIn(); + DragZoomParam dragZoom = dragZoomRequest.getDragZoomIn(); if (dragZoom == null) { dragZoom = dragZoomRequest.getDragZoomOut(); } @@ -318,7 +366,9 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent cmdXml.append("" + dragZoom.getLengthX() + "\r\n"); cmdXml.append("" + dragZoom.getLengthY() + "\r\n"); cmdXml.append("\r\n"); - cmder.dragZoomCmd(device, deviceChannel.getDeviceId(), cmdXml.toString()); + cmder.dragZoomCmd(device, deviceChannel.getDeviceId(), cmdXml.toString(), (code, msg, data) -> { + + }); responseAck(request, Response.OK); } catch (Exception e) { log.error("[命令发送失败] 拉框控制: {}", e.getMessage()); @@ -330,7 +380,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理看守位命令 */ private void handleHomePositionCmd(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的看守位命令, 通道ID: {}", channel.getGbId()); try { @@ -341,7 +391,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -370,9 +420,13 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent HomePositionRequest homePosition = loadElement(rootElement, HomePositionRequest.class); //获取整个消息主体,我们只需要修改请求头即可 HomePositionRequest.HomePosition info = homePosition.getHomePosition(); - cmder.homePositionCmd(device, deviceChannel.getDeviceId(), !"0".equals(info.getEnabled()), Integer.parseInt(info.getResetTime()), Integer.parseInt(info.getPresetIndex()), - errorResult -> onError(request, errorResult), - okResult -> onOk(request, okResult)); + cmder.homePositionCmd(device, deviceChannel.getDeviceId(), !"0".equals(info.getEnabled()), Integer.parseInt(info.getResetTime()), Integer.parseInt(info.getPresetIndex()), (code, msg, data) -> { + if (code == ErrorCode.SUCCESS.getCode()) { + onOk(request); + }else { + onError(request, code, msg); + } + }); } catch (Exception e) { log.error("[命令发送失败] 看守位设置: {}", e.getMessage()); } @@ -382,7 +436,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理告警消息 */ private void handleAlarmCmd(CommonGBChannel channel, Element rootElement, SIPRequest request) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的告警消息, 通道ID: {}", channel.getGbId()); try { @@ -393,7 +447,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -416,9 +470,13 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent } } try { - cmder.alarmCmd(device, alarmMethod, alarmType, - errorResult -> onError(request, errorResult), - okResult -> onOk(request, okResult)); + cmder.alarmResetCmd(device, alarmMethod, alarmType, (code, msg, data) -> { + if (code == ErrorCode.SUCCESS.getCode()) { + onOk(request); + }else { + onError(request, code, msg); + } + }); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 告警消息: {}", e.getMessage()); } @@ -428,7 +486,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理录像控制 */ private void handleRecordCmd(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的息录像控制, 通道ID: {}", channel.getGbId()); try { @@ -439,7 +497,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -468,9 +526,13 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent //获取整个消息主体,我们只需要修改请求头即可 String cmdString = getText(rootElement, type.getVal()); try { - cmder.recordCmd(device, deviceChannel.getDeviceId(), cmdString, - errorResult -> onError(request, errorResult), - okResult -> onOk(request, okResult)); + cmder.recordCmd(device, deviceChannel.getDeviceId(), cmdString, (code, msg, data) -> { + if (code == ErrorCode.SUCCESS.getCode()) { + onOk(request); + }else { + onError(request, code, msg); + } + }); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 录像控制: {}", e.getMessage()); } @@ -480,7 +542,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent * 处理报警布防/撤防命令 */ private void handleGuardCmd(CommonGBChannel channel, Element rootElement, SIPRequest request, DeviceControlType type) { - if (channel.getGbDeviceDbId() == 0) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 只支持国标的云台控制 log.warn("[INFO 消息] 只支持国标的报警布防/撤防命令, 通道ID: {}", channel.getGbId()); try { @@ -491,7 +553,7 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent return; } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 log.warn("[INFO 消息] 通道所属设备不存在, 通道ID: {}", channel.getGbId()); @@ -505,40 +567,47 @@ public class DeviceControlQueryMessageHandler extends SIPRequestProcessorParent //获取整个消息主体,我们只需要修改请求头即可 String cmdString = getText(rootElement, type.getVal()); try { - cmder.guardCmd(device, cmdString, - errorResult -> onError(request, errorResult), - okResult -> onOk(request, okResult)); + cmder.guardCmd(device, cmdString,(code, msg, data) -> { + if (code == ErrorCode.SUCCESS.getCode()) { + onOk(request); + }else { + onError(request, code, msg); + } + }); } catch (InvalidArgumentException | SipException | ParseException e) { log.error("[命令发送失败] 布防/撤防命令: {}", e.getMessage()); } } + + /** * 错误响应处理 * - * @param request 请求 - * @param eventResult 响应结构 */ - private void onError(SIPRequest request, SipSubscribe.EventResult eventResult) { + private void onError(SIPRequest request, Integer code, String msg) { // 失败的回复 try { - responseAck(request, eventResult.statusCode, eventResult.msg); + responseAck(request, code, msg); } catch (SipException | InvalidArgumentException | ParseException e) { log.error("[命令发送失败] 回复: {}", e.getMessage()); } } + private void onError(SIPRequest request, SipSubscribe.EventResult errorResult) { + onError(request, errorResult.statusCode, errorResult.msg); + } + /** * 成功响应处理 * * @param request 请求 - * @param eventResult 响应结构 */ - private void onOk(SIPRequest request, SipSubscribe.EventResult eventResult) { + private void onOk(SIPRequest request) { // 成功的回复 try { - responseAck(request, eventResult.statusCode); + responseAck(request, Response.OK); } catch (SipException | InvalidArgumentException | ParseException e) { log.error("[命令发送失败] 回复: {}", e.getMessage()); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java index 6dfd72db7..71e08fe57 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/BroadcastNotifyMessageHandler.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.gb28181.service.*; @@ -106,8 +107,18 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp responseAck(request, Response.NOT_FOUND, "TargetID not found"); return; } + if (channel.getDataType() != ChannelDataType.GB28181.value) { + // 只支持国标的语音喊话 + log.warn("[INFO 消息] 只支持国标的语音喊话命令, 通道ID: {}", channel.getGbId()); + try { + responseAck(request, Response.FORBIDDEN, ""); + } catch (SipException | InvalidArgumentException | ParseException e) { + log.error("[命令发送失败] 错误信息: {}", e.getMessage()); + } + return; + } // 向下级发送语音的喊话请求 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { responseAck(request, Response.NOT_FOUND, "device not found"); return; @@ -140,7 +151,7 @@ public class BroadcastNotifyMessageHandler extends SIPRequestProcessorParent imp log.info("[国标级联] 语音喊话 设备正在使用中 platform: {}, channel: {}", platform.getServerGBId(), channel.getGbDeviceId()); // 查看语音通道已经建立且已经占用 回复BYE - platformService.stopBroadcast(platform, channel, hookData.getStream(), true, hookData.getMediaServer()); + platformService.stopBroadcast(platform, channel, hookData.getApp(), hookData.getStream(), true, hookData.getMediaServer()); }else { // 查看语音通道已经建立但是未占用 broadcastCatch.setApp(hookData.getApp()); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java index 3232cae2e..04d6a0ca4 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/KeepaliveNotifyMessageHandler.java @@ -3,16 +3,18 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.DynamicTask; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.Platform; +import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo; +import com.genersoft.iot.vmp.gb28181.bean.SipMsgInfo; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.NotifyMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.SipUtils; -import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.utils.DateUtil; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.ObjectUtils; import org.dom4j.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -95,10 +97,10 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp } Device device = sipMsgInfo.getDevice(); SIPRequest request = (SIPRequest) evt.getRequest(); - if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { - log.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); - return; - } +// if (!ObjectUtils.isEmpty(device.getKeepaliveTime()) && DateUtil.getDifferenceForNow(device.getKeepaliveTime()) <= 3000L) { +// log.info("[收到心跳] 心跳发送过于频繁,已忽略 device: {}, callId: {}", device.getDeviceId(), request.getCallIdHeader().getCallId()); +// return; +// } RemoteAddressInfo remoteAddressInfo = SipUtils.getRemoteAddressFromRequest(request, userSetting.getSipUseSourceIpAsRemoteAddress()); if (!device.getIp().equalsIgnoreCase(remoteAddressInfo.getIp()) || device.getPort() != remoteAddressInfo.getPort()) { @@ -114,14 +116,6 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp }); } } - if (device.getKeepaliveTime() == null) { - device.setKeepaliveIntervalTime(60); - } else { - long lastTime = DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(device.getKeepaliveTime()); - if (System.currentTimeMillis() / 1000 - lastTime > 10) { - device.setKeepaliveIntervalTime(Long.valueOf(System.currentTimeMillis() / 1000 - lastTime).intValue()); - } - } device.setKeepaliveTime(DateUtil.getNow()); @@ -138,7 +132,8 @@ public class KeepaliveNotifyMessageHandler extends SIPRequestProcessorParent imp // 刷新过期任务 String registerExpireTaskKey = VideoManagerConstants.REGISTER_EXPIRE_TASK_KEY_PREFIX + device.getDeviceId(); // 如果三次心跳失败,则设置设备离线 - dynamicTask.startDelay(registerExpireTaskKey, () -> deviceService.offline(device.getDeviceId(), "三次心跳失败"), device.getKeepaliveIntervalTime() * 1000 * 3); + dynamicTask.startDelay(registerExpireTaskKey, () -> deviceService.offline(device.getDeviceId(), "三次心跳超时"), + device.getHeartBeatInterval() * 1000 * device.getHeartBeatCount()); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java index 6b368b725..41fa636a0 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/notify/cmd/MediaStatusNotifyMessageHandler.java @@ -14,7 +14,6 @@ import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.service.ISendRtpServerService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; import org.dom4j.Element; @@ -101,23 +100,25 @@ public class MediaStatusNotifyMessageHandler extends SIPRequestProcessorParent i // 去除监听流注销自动停止下载的监听 Hook hook = Hook.getInstance(HookType.on_media_arrival, "rtp", ssrcTransaction.getStream(), ssrcTransaction.getMediaServerId()); subscribe.removeSubscribe(hook); - // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 - SendRtpInfo sendRtpInfo = sendRtpServerService.queryByChannelId(ssrcTransaction.getChannelId(), ssrcTransaction.getPlatformId()); - if (sendRtpInfo != null) { - Platform parentPlatform = platformService.queryPlatformByServerGBId(sendRtpInfo.getTargetId()); - if (parentPlatform == null) { - log.warn("[级联消息发送]:发送MediaStatus发现上级平台{}不存在", sendRtpInfo.getTargetId()); - return; - } - CommonGBChannel channel = platformChannelService.queryChannelByPlatformIdAndChannelId(parentPlatform.getId(), sendRtpInfo.getChannelId()); - if (channel == null) { - log.warn("[级联消息发送]:发送MediaStatus发现通道{}不存在", sendRtpInfo.getChannelId()); - return; - } - try { - sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpInfo, channel); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage()); + if (ssrcTransaction.getPlatformId() != null) { + // 如果级联播放,需要给上级发送此通知 TODO 多个上级同时观看一个下级 可能存在停错的问题,需要将点播CallId进行上下级绑定 + SendRtpInfo sendRtpInfo = sendRtpServerService.queryByChannelId(ssrcTransaction.getChannelId(), ssrcTransaction.getPlatformId()); + if (sendRtpInfo != null) { + Platform parentPlatform = platformService.queryPlatformByServerGBId(sendRtpInfo.getTargetId()); + if (parentPlatform == null) { + log.warn("[级联消息发送]:发送MediaStatus发现上级平台{}不存在", sendRtpInfo.getTargetId()); + return; + } + CommonGBChannel channel = platformChannelService.queryChannelByPlatformIdAndChannelId(parentPlatform.getId(), sendRtpInfo.getChannelId()); + if (channel == null) { + log.warn("[级联消息发送]:发送MediaStatus发现通道{}不存在", sendRtpInfo.getChannelId()); + return; + } + try { + sipCommanderFroPlatform.sendMediaStatusNotify(parentPlatform, sendRtpInfo, channel); + } catch (SipException | InvalidArgumentException | ParseException e) { + log.error("[命令发送失败] 国标级联 录像播放完毕: {}", e.getMessage()); + } } } }else { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java index ca577440d..ae4366811 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/DeviceInfoQueryMessageHandler.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; @@ -93,7 +94,7 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp return; } // 判断通道类型 - if (channel.getGbDeviceDbId() == null) { + if (channel.getDataType() != ChannelDataType.GB28181.value) { // 非国标通道不支持录像回放控制 log.warn("[DeviceInfo] 非国标通道不支持录像回放控制: 通道ID: {}", channel.getGbId()); try { @@ -106,10 +107,10 @@ public class DeviceInfoQueryMessageHandler extends SIPRequestProcessorParent imp } // 根据通道ID,获取所属设备 - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { // 不存在则回复404 - log.warn("[DeviceInfo] 通道所属设备不存在, 通道ID: {}", channel.getGbDeviceDbId()); + log.warn("[DeviceInfo] 通道所属设备不存在, 通道ID: {}", channel.getDataDeviceId()); try { responseAck(request, Response.NOT_FOUND, "device not found "); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java index 79deb0423..ecabdcb14 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/query/cmd/RecordInfoQueryMessageHandler.java @@ -1,10 +1,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.query.cmd; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.DeviceChannel; import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.event.record.RecordEndEventListener; +import com.genersoft.iot.vmp.gb28181.event.record.RecordInfoEventListener; import com.genersoft.iot.vmp.gb28181.service.IDeviceChannelService; import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; @@ -52,7 +53,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp private SIPCommander commander; @Autowired - private RecordEndEventListener recordEndEventListener; + private RecordInfoEventListener recordInfoEventListener; @Override public void afterPropertiesSet() throws Exception { @@ -104,8 +105,8 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp } return; } - if (channel.getGbId() == 0 ) { - log.info("[平台查询录像记录] 不支持查询推流和拉流代理的录像数据 {}/{}", platform.getName(), channelId ); + if (channel.getDataType() != ChannelDataType.GB28181.value) { + log.info("[平台查询录像记录] 只支持查询国标28181的录像数据 {}/{}", platform.getName(), channelId ); try { responseAck(request, Response.NOT_IMPLEMENTED); // 回复未实现 } catch (SipException | InvalidArgumentException | ParseException e) { @@ -113,7 +114,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp } return; } - Device device = deviceService.getDevice(channel.getGbDeviceDbId()); + Device device = deviceService.getDevice(channel.getDataDeviceId()); if (device == null) { log.warn("[平台查询录像记录] 未找到通道对应的设备 {}/{}", platform.getName(), channelId ); try { @@ -126,7 +127,7 @@ public class RecordInfoQueryMessageHandler extends SIPRequestProcessorParent imp // 获取通道的原始信息 DeviceChannel deviceChannel = deviceChannelService.getOneForSourceById(channel.getGbId()); // 接收录像数据 - recordEndEventListener.addEndEventHandler(device.getDeviceId(), deviceChannel.getDeviceId(), (recordInfo)->{ + recordInfoEventListener.addEndEventHandler(device.getDeviceId(), deviceChannel.getDeviceId(), (recordInfo)->{ try { log.info("[国标级联] 录像查询收到数据, 通道: {},准备转发===", channelId); cmderFroPlatform.recordInfo(channel, platform, request.getFromTag(), recordInfo); diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java index 18da9cde9..6a1349d44 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/ResponseMessageHandler.java @@ -1,11 +1,20 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.event.MessageSubscribe; +import com.genersoft.iot.vmp.gb28181.event.sip.MessageEvent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageHandlerAbstract; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.MessageRequestProcessor; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import org.dom4j.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.sip.RequestEvent; + +import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; + /** * 命令类型: 请求动作的应答 * 命令类型: 设备控制, 报警通知, 设备目录信息查询, 目录信息查询, 目录收到, 设备信息查询, 设备状态信息查询 ...... @@ -18,8 +27,32 @@ public class ResponseMessageHandler extends MessageHandlerAbstract implements In @Autowired private MessageRequestProcessor messageRequestProcessor; + @Autowired + private MessageSubscribe messageSubscribe; + @Override public void afterPropertiesSet() throws Exception { messageRequestProcessor.addHandler(messageType, this); } + + @Override + public void handForDevice(RequestEvent evt, Device device, Element element) { + super.handForDevice(evt, device, element); + handMessageEvent(element, null); + } + + public void handMessageEvent(Element element, Object data) { + String cmd = getText(element, "CmdType"); + String sn = getText(element, "SN"); + MessageEvent subscribe = (MessageEvent)messageSubscribe.getSubscribe(cmd + sn); + if (subscribe != null && subscribe.getCallback() != null) { + String result = getText(element, "Result"); + if (result == null || "OK".equalsIgnoreCase(result) || data != null) { + subscribe.getCallback().run(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), data); + }else { + subscribe.getCallback().run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), result); + } + messageSubscribe.removeSubscribe(cmd + sn); + } + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java index 418534653..ffbe9075e 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/AlarmResponseMessageHandler.java @@ -4,18 +4,22 @@ import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; +import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; import org.dom4j.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.sip.InvalidArgumentException; import javax.sip.RequestEvent; +import javax.sip.SipException; +import javax.sip.message.Response; +import java.text.ParseException; @Slf4j @Component @@ -36,18 +40,18 @@ public class AlarmResponseMessageHandler extends SIPRequestProcessorParent imple @Override public void handForDevice(RequestEvent evt, Device device, Element rootElement) { - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getText().toString(); - String key = DeferredResultHolder.CALLBACK_CMD_ALARM + device.getDeviceId() + channelId; + // 回复200 OK + try { + responseAck((SIPRequest) evt.getRequest(), Response.OK); + } catch (SipException | InvalidArgumentException | ParseException e) { + log.error("[命令发送失败] 目录查询回复: {}", e.getMessage()); + } JSONObject json = new JSONObject(); XmlUtil.node2Json(rootElement, json); if (log.isDebugEnabled()) { log.debug(json.toJSONString()); } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); + responseMessageHandler.handMessageEvent(rootElement, null); } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java index 0dc38a4ac..1f6961fb1 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/CatalogResponseMessageHandler.java @@ -139,7 +139,7 @@ public class CatalogResponseMessageHandler extends SIPRequestProcessorParent imp log.info("[收到目录订阅]:但是解析失败 {}", new String(evt.getRequest().getRawContent())); continue; } - channel.setDeviceDbId(take.getDevice().getId()); + channel.setDataDeviceId(take.getDevice().getId()); if (channel.getParentId() != null && channel.getParentId().equals(sipConfig.getId())) { channel.setParentId(null); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java index ed2c8b0ab..6aa5cfa4d 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/ConfigDownloadResponseMessageHandler.java @@ -3,8 +3,8 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; @@ -22,8 +22,6 @@ import javax.sip.SipException; import javax.sip.message.Response; import java.text.ParseException; -import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; - @Slf4j @Component public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { @@ -36,6 +34,9 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar @Autowired private DeferredResultHolder deferredResultHolder; + @Autowired + private IDeviceService deviceService; + @Override public void afterPropertiesSet() throws Exception { responseMessageHandler.addHandler(cmdType, this); @@ -44,8 +45,6 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar @Override public void handForDevice(RequestEvent evt, Device device, Element element) { - String channelId = getText(element, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_CONFIGDOWNLOAD + device.getDeviceId() + channelId; try { // 回复200 OK responseAck((SIPRequest) evt.getRequest(), Response.OK); @@ -58,11 +57,33 @@ public class ConfigDownloadResponseMessageHandler extends SIPRequestProcessorPar if (log.isDebugEnabled()) { log.debug(json.toJSONString()); } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); + JSONObject jsonObject = new JSONObject(); + if (json.get("BasicParam") != null) { + jsonObject.put("BasicParam", json.getJSONObject("BasicParam")); + } + if (json.get("VideoParamOpt") != null) { + jsonObject.put("VideoParamOpt", json.getJSONObject("VideoParamOpt")); + } + if (json.get("SVACEncodeConfig") != null) { + jsonObject.put("SVACEncodeConfig", json.getJSONObject("SVACEncodeConfig")); + } + if (json.get("SVACDecodeConfig") != null) { + jsonObject.put("SVACDecodeConfig", json.getJSONObject("SVACDecodeConfig")); + } + responseMessageHandler.handMessageEvent(element, jsonObject); + + JSONObject basicParam = json.getJSONObject("BasicParam"); + if (basicParam != null) { + Integer heartBeatInterval = basicParam.getInteger("HeartBeatInterval"); + Integer heartBeatCount = basicParam.getInteger("HeartBeatCount"); + Integer positionCapability = basicParam.getInteger("PositionCapability"); + device.setHeartBeatInterval(heartBeatInterval); + device.setHeartBeatCount(heartBeatCount); + device.setPositionCapability(positionCapability); + + deviceService.updateDeviceHeartInfo(device); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java deleted file mode 100755 index 453d8066f..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceConfigResponseMessageHandler.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; - -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; -import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; -import lombok.extern.slf4j.Slf4j; -import org.dom4j.Element; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.sip.RequestEvent; - -import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; - -@Slf4j -@Component -public class DeviceConfigResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { - - private final String cmdType = "DeviceConfig"; - - @Autowired - private ResponseMessageHandler responseMessageHandler; - - @Autowired - private DeferredResultHolder deferredResultHolder; - - @Override - public void afterPropertiesSet() throws Exception { - responseMessageHandler.addHandler(cmdType, this); - } - - @Override - public void handForDevice(RequestEvent evt, Device device, Element element) { - JSONObject json = new JSONObject(); - XmlUtil.node2Json(element, json); - String channelId = getText(element, "DeviceID"); - if (log.isDebugEnabled()) { - log.debug(json.toJSONString()); - } - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONFIG + device.getDeviceId() + channelId; - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); - } - - @Override - public void handForPlatform(RequestEvent evt, Platform parentPlatform, Element rootElement) { - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java deleted file mode 100755 index f3f489781..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceControlResponseMessageHandler.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.cmd; - -import com.alibaba.fastjson2.JSONObject; -import com.genersoft.iot.vmp.gb28181.bean.Device; -import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; -import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; -import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; -import gov.nist.javax.sip.message.SIPRequest; -import lombok.extern.slf4j.Slf4j; -import org.dom4j.Element; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.sip.InvalidArgumentException; -import javax.sip.RequestEvent; -import javax.sip.SipException; -import javax.sip.message.Response; -import java.text.ParseException; - -import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; - -@Slf4j -@Component -public class DeviceControlResponseMessageHandler extends SIPRequestProcessorParent implements InitializingBean, IMessageHandler { - - private final String cmdType = "DeviceControl"; - - @Autowired - private ResponseMessageHandler responseMessageHandler; - - @Autowired - private DeferredResultHolder deferredResultHolder; - - @Override - public void afterPropertiesSet() throws Exception { - responseMessageHandler.addHandler(cmdType, this); - } - - @Override - public void handForDevice(RequestEvent evt, Device device, Element element) { - // 此处是对本平台发出DeviceControl指令的应答 - try { - responseAck((SIPRequest) evt.getRequest(), Response.OK); - } catch (SipException | InvalidArgumentException | ParseException e) { - log.error("[命令发送失败] 国标级联 设备控制: {}", e.getMessage()); - } - JSONObject json = new JSONObject(); - String channelId = getText(element, "DeviceID"); - String result = getText(element, "Result"); - - RequestMessage msg = new RequestMessage(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICECONTROL + device.getDeviceId() + channelId; - msg.setKey(key); - if ("OK".equalsIgnoreCase(result)) { - msg.setData(WVPResult.success()); - }else { - msg.setData(WVPResult.fail(ErrorCode.ERROR100)); - } - if (log.isDebugEnabled()) { - log.debug(json.toJSONString()); - } - deferredResultHolder.invokeAllResult(msg); - - } - - @Override - public void handForPlatform(RequestEvent evt, Platform parentPlatform, Element rootElement) { - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java index 9db37b41f..24e7f5804 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceInfoResponseMessageHandler.java @@ -2,12 +2,10 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; -import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; import org.dom4j.DocumentException; @@ -37,9 +35,6 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent @Autowired private ResponseMessageHandler responseMessageHandler; - @Autowired - private DeferredResultHolder deferredResultHolder; - @Autowired private IDeviceService deviceService; @@ -70,23 +65,17 @@ public class DeviceInfoResponseMessageHandler extends SIPRequestProcessorParent } return; } - Element deviceIdElement = rootElement.element("DeviceID"); - String channelId = deviceIdElement.getTextTrim(); - String key = DeferredResultHolder.CALLBACK_CMD_DEVICEINFO + device.getDeviceId() + channelId; device.setName(getText(rootElement, "DeviceName")); device.setManufacturer(getText(rootElement, "Manufacturer")); device.setModel(getText(rootElement, "Model")); device.setFirmware(getText(rootElement, "Firmware")); if (ObjectUtils.isEmpty(device.getStreamMode())) { - device.setStreamMode("UDP"); + device.setStreamMode("TCP-PASSIVE"); } deviceService.updateDevice(device); + responseMessageHandler.handMessageEvent(rootElement, device); - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(device); - deferredResultHolder.invokeAllResult(msg); } catch (DocumentException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java index c6e366445..affd22f55 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/DeviceStatusResponseMessageHandler.java @@ -3,14 +3,11 @@ package com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.respon import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; -import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; import com.genersoft.iot.vmp.gb28181.utils.XmlUtil; -import com.genersoft.iot.vmp.gb28181.service.IDeviceService; -import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import gov.nist.javax.sip.message.SIPRequest; import lombok.extern.slf4j.Slf4j; import org.dom4j.Element; @@ -33,15 +30,9 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen @Autowired private ResponseMessageHandler responseMessageHandler; - @Autowired - private DeferredResultHolder deferredResultHolder; - @Autowired private IDeviceService deviceService; - @Autowired - private IRedisCatchStorage redisCatchStorage; - @Override public void afterPropertiesSet() throws Exception { responseMessageHandler.addHandler(cmdType, this); @@ -60,24 +51,15 @@ public class DeviceStatusResponseMessageHandler extends SIPRequestProcessorParen } catch (SipException | InvalidArgumentException | ParseException e) { log.error("[命令发送失败] 国标级联 设备状态应答回复200OK: {}", e.getMessage()); } - Element deviceIdElement = element.element("DeviceID"); Element onlineElement = element.element("Online"); - String channelId = deviceIdElement.getText(); JSONObject json = new JSONObject(); XmlUtil.node2Json(element, json); if (log.isDebugEnabled()) { log.debug(json.toJSONString()); } String text = onlineElement.getText(); - if ("ONLINE".equalsIgnoreCase(text.trim())) { - deviceService.online(device, null); - }else { - deviceService.offline(device.getDeviceId(), "设备状态查询结果:" + text.trim()); - } - RequestMessage msg = new RequestMessage(); - msg.setKey(DeferredResultHolder.CALLBACK_CMD_DEVICESTATUS + device.getDeviceId()); - msg.setData(json); - deferredResultHolder.invokeAllResult(msg); + responseMessageHandler.handMessageEvent(element, text); + } @Override diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java index 21626d8bf..5e154f6e7 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/PresetQueryResponseMessageHandler.java @@ -4,7 +4,6 @@ import com.genersoft.iot.vmp.gb28181.bean.Device; import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.Preset; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; -import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.IMessageHandler; import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.response.ResponseMessageHandler; @@ -25,8 +24,6 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import static com.genersoft.iot.vmp.gb28181.utils.XmlUtil.getText; - /** * 设备预置位查询应答 */ @@ -68,8 +65,6 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent Element presetListNumElement = rootElement.element("PresetList"); Element snElement = rootElement.element("SN"); //该字段可能为通道或则设备的id - String deviceId = getText(rootElement, "DeviceID"); - String key = DeferredResultHolder.CALLBACK_CMD_PRESETQUERY + deviceId; if (snElement == null || presetListNumElement == null) { try { responseAck(request, Response.BAD_REQUEST, "xml error"); @@ -98,10 +93,7 @@ public class PresetQueryResponseMessageHandler extends SIPRequestProcessorParent presetQuerySipReqList.add(presetQuerySipReq); } } - RequestMessage requestMessage = new RequestMessage(); - requestMessage.setKey(key); - requestMessage.setData(presetQuerySipReqList); - deferredResultHolder.invokeAllResult(requestMessage); + responseMessageHandler.handMessageEvent(rootElement, presetQuerySipReqList); try { responseAck(request, Response.OK); } catch (InvalidArgumentException | ParseException | SipException e) { diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java index 655c05511..0ab97e87f 100755 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/message/response/cmd/RecordInfoResponseMessageHandler.java @@ -6,6 +6,8 @@ import com.genersoft.iot.vmp.gb28181.bean.Platform; import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; import com.genersoft.iot.vmp.gb28181.bean.RecordItem; import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.event.record.RecordInfoEndEvent; +import com.genersoft.iot.vmp.gb28181.event.record.RecordInfoEvent; import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder; import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage; import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent; @@ -19,6 +21,7 @@ import org.dom4j.Element; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; @@ -48,14 +51,7 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent private ResponseMessageHandler responseMessageHandler; @Autowired - private DeferredResultHolder deferredResultHolder; - - @Autowired - private EventPublisher eventPublisher; - - @Qualifier("taskExecutor") - @Autowired - private ThreadPoolTaskExecutor taskExecutor; + private ApplicationEventPublisher applicationEventPublisher; @Autowired private RedisTemplate redisTemplate; @@ -75,88 +71,89 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent }catch (SipException | InvalidArgumentException | ParseException e) { log.error("[命令发送失败] 国标级联 国标录像: {}", e.getMessage()); } - taskExecutor.execute(()->{ - try { - String sn = getText(rootElement, "SN"); - String channelId = getText(rootElement, "DeviceID"); - RecordInfo recordInfo = new RecordInfo(); - recordInfo.setChannelId(channelId); - recordInfo.setDeviceId(device.getDeviceId()); - recordInfo.setSn(sn); - recordInfo.setName(getText(rootElement, "Name")); - String sumNumStr = getText(rootElement, "SumNum"); - int sumNum = 0; - if (!ObjectUtils.isEmpty(sumNumStr)) { - sumNum = Integer.parseInt(sumNumStr); - } - recordInfo.setSumNum(sumNum); - Element recordListElement = rootElement.element("RecordList"); - if (recordListElement == null || sumNum == 0) { - log.info("无录像数据"); - recordInfo.setCount(sumNum); - eventPublisher.recordEndEventPush(recordInfo); - releaseRequest(device.getDeviceId(), sn,recordInfo); - } else { - Iterator recordListIterator = recordListElement.elementIterator(); - if (recordListIterator != null) { - List recordList = new ArrayList<>(); - // 遍历DeviceList - while (recordListIterator.hasNext()) { - Element itemRecord = recordListIterator.next(); - Element recordElement = itemRecord.element("DeviceID"); - if (recordElement == null) { - log.info("记录为空,下一个..."); - continue; - } - RecordItem record = new RecordItem(); - record.setDeviceId(getText(itemRecord, "DeviceID")); - record.setName(getText(itemRecord, "Name")); - record.setFilePath(getText(itemRecord, "FilePath")); - record.setFileSize(getText(itemRecord, "FileSize")); - record.setAddress(getText(itemRecord, "Address")); - - String startTimeStr = getText(itemRecord, "StartTime"); - record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); - - String endTimeStr = getText(itemRecord, "EndTime"); - record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); - - record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 - : Integer.parseInt(getText(itemRecord, "Secrecy"))); - record.setType(getText(itemRecord, "Type")); - record.setRecorderId(getText(itemRecord, "RecorderID")); - recordList.add(record); - } - Map map = recordList.stream() - .filter(record -> record.getDeviceId() != null) - .collect(Collectors.toMap(record -> record.getStartTime()+ record.getEndTime(), UJson::writeJson)); - // 获取任务结果数据 - String resKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_PRE + channelId + sn; - redisTemplate.opsForHash().putAll(resKey, map); - redisTemplate.expire(resKey, recordInfoTtl, TimeUnit.SECONDS); - String resCountKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_COUNT_PRE + channelId + sn; - long incr = redisTemplate.opsForValue().increment(resCountKey, map.size()); - redisTemplate.expire(resCountKey, recordInfoTtl, TimeUnit.SECONDS); - recordInfo.setRecordList(recordList); - recordInfo.setCount(Math.toIntExact(incr)); - eventPublisher.recordEndEventPush(recordInfo); - if (incr < sumNum) { - return; - } - // 已接收完成 - List resList = redisTemplate.opsForHash().entries(resKey).values().stream().map(e -> UJson.readJson(e.toString(), RecordItem.class)).collect(Collectors.toList()); - if (resList.size() < sumNum) { - return; - } - recordInfo.setRecordList(resList); - releaseRequest(device.getDeviceId(), sn,recordInfo); - } - } - } catch (Exception e) { - log.error("[国标录像] 发现未处理的异常, \r\n{}", evt.getRequest()); - log.error("[国标录像] 异常内容: ", e); + try { + String sn = getText(rootElement, "SN"); + String channelId = getText(rootElement, "DeviceID"); + RecordInfo recordInfo = new RecordInfo(); + recordInfo.setChannelId(channelId); + recordInfo.setDeviceId(device.getDeviceId()); + recordInfo.setSn(sn); + recordInfo.setName(getText(rootElement, "Name")); + String sumNumStr = getText(rootElement, "SumNum"); + int sumNum = 0; + if (!ObjectUtils.isEmpty(sumNumStr)) { + sumNum = Integer.parseInt(sumNumStr); } - }); + recordInfo.setSumNum(sumNum); + Element recordListElement = rootElement.element("RecordList"); + if (recordListElement == null || sumNum == 0) { + log.info("无录像数据"); + recordInfo.setCount(sumNum); + recordInfoEventPush(recordInfo); + recordInfoEndEventPush(recordInfo); + } else { + Iterator recordListIterator = recordListElement.elementIterator(); + if (recordListIterator != null) { + List recordList = new ArrayList<>(); + // 遍历DeviceList + while (recordListIterator.hasNext()) { + Element itemRecord = recordListIterator.next(); + Element recordElement = itemRecord.element("DeviceID"); + if (recordElement == null) { + log.info("记录为空,下一个..."); + continue; + } + RecordItem record = new RecordItem(); + record.setDeviceId(getText(itemRecord, "DeviceID")); + record.setName(getText(itemRecord, "Name")); + record.setFilePath(getText(itemRecord, "FilePath")); + record.setFileSize(getText(itemRecord, "FileSize")); + record.setAddress(getText(itemRecord, "Address")); + + String startTimeStr = getText(itemRecord, "StartTime"); + record.setStartTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(startTimeStr)); + + String endTimeStr = getText(itemRecord, "EndTime"); + record.setEndTime(DateUtil.ISO8601Toyyyy_MM_dd_HH_mm_ss(endTimeStr)); + + record.setSecrecy(itemRecord.element("Secrecy") == null ? 0 + : Integer.parseInt(getText(itemRecord, "Secrecy"))); + record.setType(getText(itemRecord, "Type")); + record.setRecorderId(getText(itemRecord, "RecorderID")); + recordList.add(record); + } + Map map = recordList.stream() + .filter(record -> record.getDeviceId() != null) + .collect(Collectors.toMap(record -> record.getStartTime()+ record.getEndTime(), UJson::writeJson)); + // 获取任务结果数据 + String resKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_PRE + channelId + sn; + redisTemplate.opsForHash().putAll(resKey, map); + redisTemplate.expire(resKey, recordInfoTtl, TimeUnit.SECONDS); + String resCountKey = VideoManagerConstants.REDIS_RECORD_INFO_RES_COUNT_PRE + channelId + sn; + Long incr = redisTemplate.opsForValue().increment(resCountKey, map.size()); + if (incr == null) { + incr = 0L; + } + redisTemplate.expire(resCountKey, recordInfoTtl, TimeUnit.SECONDS); + recordInfo.setRecordList(recordList); + recordInfo.setCount(Math.toIntExact(incr)); + recordInfoEventPush(recordInfo); + if (incr < sumNum) { + return; + } + // 已接收完成 + List resList = redisTemplate.opsForHash().entries(resKey).values().stream().map(e -> UJson.readJson(e.toString(), RecordItem.class)).collect(Collectors.toList()); + if (resList.size() < sumNum) { + return; + } + recordInfo.setRecordList(resList); + recordInfoEndEventPush(recordInfo); + } + } + } catch (Exception e) { + log.error("[国标录像] 发现未处理的异常, \r\n{}", evt.getRequest()); + log.error("[国标录像] 异常内容: ", e); + } } @Override @@ -164,18 +161,31 @@ public class RecordInfoResponseMessageHandler extends SIPRequestProcessorParent } - public void releaseRequest(String deviceId, String sn,RecordInfo recordInfo){ - String key = DeferredResultHolder.CALLBACK_CMD_RECORDINFO + deviceId + sn; - // 对数据进行排序 - if(recordInfo!=null && recordInfo.getRecordList()!=null) { + private void recordInfoEventPush(RecordInfo recordInfo) { + if (recordInfo == null) { + return; + } + if(recordInfo.getRecordList() != null) { Collections.sort(recordInfo.getRecordList()); }else{ recordInfo.setRecordList(new ArrayList<>()); } + RecordInfoEvent outEvent = new RecordInfoEvent(this); + outEvent.setRecordInfo(recordInfo); + applicationEventPublisher.publishEvent(outEvent); + } - RequestMessage msg = new RequestMessage(); - msg.setKey(key); - msg.setData(recordInfo); - deferredResultHolder.invokeAllResult(msg); + private void recordInfoEndEventPush(RecordInfo recordInfo) { + if (recordInfo == null) { + return; + } + if(recordInfo.getRecordList() != null) { + Collections.sort(recordInfo.getRecordList()); + }else{ + recordInfo.setRecordList(new ArrayList<>()); + } + RecordInfoEndEvent outEvent = new RecordInfoEndEvent(this); + outEvent.setRecordInfo(recordInfo); + applicationEventPublisher.publishEvent(outEvent); } } diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java deleted file mode 100755 index e0bb1f895..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/ITimeoutProcessor.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.event.timeout; - -import javax.sip.TimeoutEvent; - -public interface ITimeoutProcessor { - void process(TimeoutEvent event); -} diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java b/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java deleted file mode 100755 index c36a2e54b..000000000 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/timeout/impl/TimeoutProcessorImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -package com.genersoft.iot.vmp.gb28181.transmit.event.timeout.impl; - -import com.genersoft.iot.vmp.gb28181.event.SipSubscribe; -import com.genersoft.iot.vmp.gb28181.event.sip.SipEvent; -import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver; -import com.genersoft.iot.vmp.gb28181.transmit.event.timeout.ITimeoutProcessor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import javax.sip.TimeoutEvent; -import javax.sip.header.CallIdHeader; - -@Slf4j -@Component -public class TimeoutProcessorImpl implements InitializingBean, ITimeoutProcessor { - - @Autowired - private SIPProcessorObserver processorObserver; - - @Autowired - private SipSubscribe sipSubscribe; - - @Override - public void afterPropertiesSet() throws Exception { - processorObserver.addTimeoutProcessor(this); - } - - @Override - public void process(TimeoutEvent event) { - try { - // TODO Auto-generated method stub - CallIdHeader callIdHeader = event.getClientTransaction().getDialog().getCallId(); - String callId = callIdHeader.getCallId(); - SipEvent sipEvent = sipSubscribe.getSubscribe(callId); - if (sipEvent != null && sipEvent.getErrorEvent() != null) { - SipSubscribe.EventResult timeoutEventEventResult = new SipSubscribe.EventResult<>(event); - sipEvent.getErrorEvent().response(timeoutEventEventResult); - sipSubscribe.removeSubscribe(callId); - } - } catch (Exception e) { - log.error("[超时事件失败]: {}", e.getMessage()); - } - } -} diff --git a/src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java b/src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java index 9c3fd2868..def0c0eb0 100644 --- a/src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java +++ b/src/main/java/com/genersoft/iot/vmp/jt1078/util/ClassUtil.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.jt1078.util; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; @@ -12,6 +13,12 @@ import java.util.List; @Slf4j public class ClassUtil { + public static ConfigurableApplicationContext context; + + public static T getBean(String beanName, Class clazz) { + return context.getBean(beanName, clazz); + } + public static Object getBean(Class clazz) { if (clazz != null) { try { diff --git a/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java b/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java index b9f7c08ef..ba27fb350 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java +++ b/src/main/java/com/genersoft/iot/vmp/media/MediaServerConfig.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.media; import com.genersoft.iot.vmp.conf.MediaConfig; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.mediaServer.MediaServerChangeEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; @@ -30,6 +31,9 @@ public class MediaServerConfig implements CommandLineRunner { @Autowired private MediaConfig mediaConfig; + @Autowired + private UserSetting userSetting; + @Override public void run(String... strings) throws Exception { @@ -37,6 +41,7 @@ public class MediaServerConfig implements CommandLineRunner { mediaServerService.clearMediaServerForOnline(); MediaServer defaultMediaServer = mediaServerService.getDefaultMediaServer(); MediaServer mediaSerItemInConfig = mediaConfig.getMediaSerItem(); + mediaSerItemInConfig.setServerId(userSetting.getServerId()); if (defaultMediaServer != null && mediaSerItemInConfig.getId().equals(defaultMediaServer.getId())) { mediaServerService.update(mediaSerItemInConfig); }else { diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java index b8da56788..12921dcc8 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaInfo.java @@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.media.zlm.dto.hook.OnStreamChangedHookParam; import com.genersoft.iot.vmp.utils.MediaServerUtils; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; +import org.springframework.util.ObjectUtils; import java.util.List; import java.util.Map; @@ -47,8 +48,10 @@ public class MediaInfo { private Long duration; @Schema(description = "在线") private Boolean online; - @Schema(description = "unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7") + @Schema(description = "unknown = 0,rtmp_push=1,rtsp_push=2,rtp_push=3,pull=4,ffmpeg_pull=5,mp4_vod=6,device_chn=7,rtc_push=8") private Integer originType; + @Schema(description = "originType的文本描述") + private String originTypeStr; @Schema(description = "产生流的源流地址") private String originUrl; @Schema(description = "存活时间,单位秒") @@ -77,11 +80,14 @@ public class MediaInfo { Boolean online = jsonObject.getBoolean("online"); Integer originType = jsonObject.getInteger("originType"); String originUrl = jsonObject.getString("originUrl"); + String originTypeStr = jsonObject.getString("originTypeStr"); Long aliveSecond = jsonObject.getLong("aliveSecond"); String params = jsonObject.getString("params"); Long bytesSpeed = jsonObject.getLong("bytesSpeed"); if (totalReaderCount != null) { mediaInfo.setReaderCount(totalReaderCount); + } else { + mediaInfo.setReaderCount(0); } if (online != null) { mediaInfo.setOnline(online); @@ -89,8 +95,8 @@ public class MediaInfo { if (originType != null) { mediaInfo.setOriginType(originType); } - if (originUrl != null) { - mediaInfo.setOriginUrl(originUrl); + if (originTypeStr != null) { + mediaInfo.setOriginTypeStr(originTypeStr); } if (aliveSecond != null) { @@ -106,63 +112,62 @@ public class MediaInfo { } } JSONArray jsonArray = jsonObject.getJSONArray("tracks"); - if (jsonArray.isEmpty()) { - return null; - } - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject trackJson = jsonArray.getJSONObject(i); - Integer channels = trackJson.getInteger("channels"); - Integer codecId = trackJson.getInteger("codec_id"); - Integer codecType = trackJson.getInteger("codec_type"); - Integer sampleRate = trackJson.getInteger("sample_rate"); - Integer height = trackJson.getInteger("height"); - Integer width = trackJson.getInteger("width"); - Integer fps = trackJson.getInteger("fps"); - Integer loss = trackJson.getInteger("loss"); - Integer frames = trackJson.getInteger("frames"); - Long keyFrames = trackJson.getLongValue("key_frames"); - Integer gop_interval_ms = trackJson.getInteger("gop_interval_ms"); - Long gop_size = trackJson.getLongValue("gop_size"); + if (!ObjectUtils.isEmpty(jsonArray)) { + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject trackJson = jsonArray.getJSONObject(i); + Integer channels = trackJson.getInteger("channels"); + Integer codecId = trackJson.getInteger("codec_id"); + Integer codecType = trackJson.getInteger("codec_type"); + Integer sampleRate = trackJson.getInteger("sample_rate"); + Integer height = trackJson.getInteger("height"); + Integer width = trackJson.getInteger("width"); + Integer fps = trackJson.getInteger("fps"); + Integer loss = trackJson.getInteger("loss"); + Integer frames = trackJson.getInteger("frames"); + Long keyFrames = trackJson.getLongValue("key_frames"); + Integer gop_interval_ms = trackJson.getInteger("gop_interval_ms"); + Long gop_size = trackJson.getLongValue("gop_size"); - Long duration = trackJson.getLongValue("duration"); - if (channels != null) { - mediaInfo.setAudioChannels(channels); - } - if (sampleRate != null) { - mediaInfo.setAudioSampleRate(sampleRate); - } - if (height != null) { - mediaInfo.setHeight(height); - } - if (width != null) { - mediaInfo.setWidth(width); - } - if (fps != null) { - mediaInfo.setFps(fps); - } - if (loss != null) { - mediaInfo.setLoss(loss); - } - if (duration > 0L) { - mediaInfo.setDuration(duration); - } - if (codecId != null) { - switch (codecId) { - case 0: - mediaInfo.setVideoCodec("H264"); - break; - case 1: - mediaInfo.setVideoCodec("H265"); - break; - case 2: - mediaInfo.setAudioCodec("AAC"); - break; - case 3: - mediaInfo.setAudioCodec("G711A"); - break; - case 4: - mediaInfo.setAudioCodec("G711U"); - break; + Long duration = trackJson.getLongValue("duration"); + if (channels != null) { + mediaInfo.setAudioChannels(channels); + } + if (sampleRate != null) { + mediaInfo.setAudioSampleRate(sampleRate); + } + if (height != null) { + mediaInfo.setHeight(height); + } + if (width != null) { + mediaInfo.setWidth(width); + } + if (fps != null) { + mediaInfo.setFps(fps); + } + if (loss != null) { + mediaInfo.setLoss(loss); + } + if (duration > 0L) { + mediaInfo.setDuration(duration); + } + if (codecId != null) { + switch (codecId) { + case 0: + mediaInfo.setVideoCodec("H264"); + break; + case 1: + mediaInfo.setVideoCodec("H265"); + break; + case 2: + mediaInfo.setAudioCodec("AAC"); + break; + case 3: + mediaInfo.setAudioCodec("G711A"); + break; + case 4: + mediaInfo.setAudioCodec("G711U"); + break; + } } } } @@ -179,6 +184,8 @@ public class MediaInfo { mediaInfo.setReaderCount(param.getTotalReaderCount()); mediaInfo.setOnline(param.isRegist()); mediaInfo.setOriginType(param.getOriginType()); + mediaInfo.setOriginTypeStr(param.getOriginTypeStr()); + mediaInfo.setOriginUrl(param.getOriginUrl()); mediaInfo.setOriginUrl(param.getOriginUrl()); mediaInfo.setAliveSecond(param.getAliveSecond()); mediaInfo.setBytesSpeed(param.getBytesSpeed()); diff --git a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java index e6faac364..2660cb6a9 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java +++ b/src/main/java/com/genersoft/iot/vmp/media/bean/MediaServer.java @@ -103,6 +103,9 @@ public class MediaServer { @Schema(description = "转码的前缀") private String transcodeSuffix; + @Schema(description = "服务Id") + private String serverId; + public MediaServer() { } @@ -388,4 +391,12 @@ public class MediaServer { public void setTranscodeSuffix(String transcodeSuffix) { this.transcodeSuffix = transcodeSuffix; } + + public String getServerId() { + return serverId; + } + + public void setServerId(String serverId) { + this.serverId = serverId; + } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java index c6c597b07..0a089cf2f 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/media/service/impl/MediaServerServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.media.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.common.VideoManagerConstants; @@ -50,7 +49,6 @@ import java.util.*; */ @Slf4j @Service -@DS("master") public class MediaServerServiceImpl implements IMediaServerService { @Autowired @@ -197,7 +195,7 @@ public class MediaServerServiceImpl implements IMediaServerService { } else { rtpServerPort = mediaServer.getRtpProxyPort(); } - return new SSRCInfo(rtpServerPort, ssrc, streamId, null); + return new SSRCInfo(rtpServerPort, ssrc, "rtp", streamId, null); } @Override @@ -305,7 +303,7 @@ public class MediaServerServiceImpl implements IMediaServerService { mediaServerMapper.update(mediaSerItem); MediaServer mediaServerInRedis = getOne(mediaSerItem.getId()); // 获取完整数据 - MediaServer mediaServerInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId()); + MediaServer mediaServerInDataBase = mediaServerMapper.queryOne(mediaSerItem.getId(), userSetting.getServerId()); if (mediaServerInDataBase == null) { return; } @@ -352,7 +350,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public List getAll() { - List mediaServerList = mediaServerMapper.queryAll(); + List mediaServerList = mediaServerMapper.queryAll(userSetting.getServerId()); if (mediaServerList.isEmpty()) { return new ArrayList<>(); } @@ -368,7 +366,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public List getAllFromDatabase() { - return mediaServerMapper.queryAll(); + return mediaServerMapper.queryAll(userSetting.getServerId()); } @Override @@ -405,7 +403,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public MediaServer getDefaultMediaServer() { - return mediaServerMapper.queryDefault(); + return mediaServerMapper.queryDefault(userSetting.getServerId()); } @Override @@ -425,7 +423,7 @@ public class MediaServerServiceImpl implements IMediaServerService { log.info("[添加媒体节点] 失败, mediaServer的类型:为空"); return; } - if (mediaServerMapper.queryOne(mediaServer.getId()) != null) { + if (mediaServerMapper.queryOne(mediaServer.getId(), userSetting.getServerId()) != null) { log.info("[添加媒体节点] 失败, 媒体服务ID已存在,请修改媒体服务器配置, {}", mediaServer.getId()); throw new ControllerException(ErrorCode.ERROR100.getCode(),"保存失败,媒体服务ID [ " + mediaServer.getId() + " ] 已存在,请修改媒体服务器配置"); } @@ -523,7 +521,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public MediaServer checkMediaServer(String ip, int port, String secret, String type) { - if (mediaServerMapper.queryOneByHostAndPort(ip, port) != null) { + if (mediaServerMapper.queryOneByHostAndPort(ip, port, userSetting.getServerId()) != null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "此连接已存在"); } @@ -534,7 +532,7 @@ public class MediaServerServiceImpl implements IMediaServerService { } MediaServer mediaServer = mediaNodeServerService.checkMediaServer(ip, port, secret); if (mediaServer != null) { - if (mediaServerMapper.queryOne(mediaServer.getId()) != null) { + if (mediaServerMapper.queryOne(mediaServer.getId(), userSetting.getServerId()) != null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "媒体服务ID [" + mediaServer.getId() + " ] 已存在,请修改媒体服务器配置"); } } @@ -562,7 +560,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public void delete(MediaServer mediaServer) { - mediaServerMapper.delOne(mediaServer.getId()); + mediaServerMapper.delOne(mediaServer.getId(), userSetting.getServerId()); redisTemplate.opsForZSet().remove(VideoManagerConstants.ONLINE_MEDIA_SERVERS_PREFIX + userSetting.getServerId(), mediaServer.getId()); String key = VideoManagerConstants.MEDIA_SERVER_PREFIX + userSetting.getServerId() + ":" + mediaServer.getId(); redisTemplate.delete(key); @@ -574,13 +572,13 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public MediaServer getOneFromDatabase(String mediaServerId) { - return mediaServerMapper.queryOne(mediaServerId); + return mediaServerMapper.queryOne(mediaServerId, userSetting.getServerId()); } @Override public void syncCatchFromDatabase() { List allInCatch = getAllOnlineList(); - List allInDatabase = mediaServerMapper.queryAll(); + List allInDatabase = mediaServerMapper.queryAll(userSetting.getServerId()); Map mediaServerMap = new HashMap<>(); for (MediaServer mediaServer : allInDatabase) { @@ -608,7 +606,7 @@ public class MediaServerServiceImpl implements IMediaServerService { @Override public List getAllWithAssistPort() { - return mediaServerMapper.queryAllWithAssistPort(); + return mediaServerMapper.queryAllWithAssistPort(userSetting.getServerId()); } @@ -824,7 +822,25 @@ public class MediaServerServiceImpl implements IMediaServerService { } streamInfoResult.setMediaServer(mediaServer); - String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId; + Map param = new HashMap<>(); + if (!ObjectUtils.isEmpty(callId)) { + param.put("callId", callId); + } + if (mediaInfo != null && !ObjectUtils.isEmpty(mediaInfo.getOriginTypeStr())) { + param.put("originTypeStr", mediaInfo.getOriginTypeStr()); + } + StringBuilder callIdParamBuilder = new StringBuilder(); + if (!param.isEmpty()) { + callIdParamBuilder.append("?"); + for (Map.Entry entry : param.entrySet()) { + callIdParamBuilder.append(entry.getKey()).append("=").append(entry.getValue()); + callIdParamBuilder.append("&"); + } + callIdParamBuilder.deleteCharAt(callIdParamBuilder.length() - 1); + } + + String callIdParam = callIdParamBuilder.toString(); + streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam); streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam); diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java index 44c21350e..54546a526 100644 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/ZLMMediaNodeServerService.java @@ -89,6 +89,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { @Override public MediaServer checkMediaServer(String ip, int port, String secret) { MediaServer mediaServer = new MediaServer(); + mediaServer.setServerId(userSetting.getServerId()); mediaServer.setIp(ip); mediaServer.setHttpPort(port); mediaServer.setFlvPort(port); @@ -178,15 +179,17 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { JSONObject mediaList = zlmresTfulUtils.getMediaList(mediaServer, app, stream); if (mediaList != null) { if (mediaList.getInteger("code") == 0) { - JSONArray data = mediaList.getJSONArray("data"); - if (data == null) { + JSONArray dataArray = mediaList.getJSONArray("data"); + if (dataArray == null) { return streamInfoList; } - JSONObject mediaJSON = data.getJSONObject(0); - MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer, userSetting.getServerId()); - StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, app, stream, mediaInfo, callId, true); - if (streamInfo != null) { - streamInfoList.add(streamInfo); + for (int i = 0; i < dataArray.size(); i++) { + JSONObject mediaJSON = dataArray.getJSONObject(0); + MediaInfo mediaInfo = MediaInfo.getInstance(mediaJSON, mediaServer, userSetting.getServerId()); + StreamInfo streamInfo = getStreamInfoByAppAndStream(mediaServer, mediaInfo.getApp(), mediaInfo.getStream(), mediaInfo, callId, true); + if (streamInfo != null) { + streamInfoList.add(streamInfo); + } } } } @@ -201,7 +204,26 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { String addr = mediaServer.getStreamIp(); streamInfoResult.setIp(addr); streamInfoResult.setMediaServer(mediaServer); - String callIdParam = ObjectUtils.isEmpty(callId)?"":"?callId=" + callId; + + Map param = new HashMap<>(); + if (!ObjectUtils.isEmpty(callId)) { + param.put("callId", callId); + } + if (mediaInfo != null && !ObjectUtils.isEmpty(mediaInfo.getOriginTypeStr())) { + param.put("originTypeStr", mediaInfo.getOriginTypeStr()); + } + StringBuilder callIdParamBuilder = new StringBuilder(); + if (!param.isEmpty()) { + callIdParamBuilder.append("?"); + for (Map.Entry entry : param.entrySet()) { + callIdParamBuilder.append(entry.getKey()).append("=").append(entry.getValue()); + callIdParamBuilder.append("&"); + } + callIdParamBuilder.deleteCharAt(callIdParamBuilder.length() - 1); + } + + String callIdParam = callIdParamBuilder.toString(); + streamInfoResult.setRtmp(addr, mediaServer.getRtmpPort(),mediaServer.getRtmpSSlPort(), app, stream, callIdParam); streamInfoResult.setRtsp(addr, mediaServer.getRtspPort(),mediaServer.getRtspSSLPort(), app, stream, callIdParam); String flvFile = String.format("%s/%s.live.flv%s", app, stream, callIdParam); @@ -215,6 +237,7 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { streamInfoResult.setMediaInfo(mediaInfo); if (mediaInfo != null) { streamInfoResult.setOriginType(mediaInfo.getOriginType()); + streamInfoResult.setOriginTypeStr(mediaInfo.getOriginTypeStr()); } return streamInfoResult; } @@ -421,8 +444,11 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { port = mediaServer.getRtspPort(); schemaForUri = schema; }else if (schema.equalsIgnoreCase("flv")) { + if (mediaServer.getRtmpPort() == 0) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), "ffmpeg拉流代理播放时发现未设置rtmp端口"); + } port = mediaServer.getRtmpPort(); - schemaForUri = schema; + schemaForUri = "rtmp"; }else { port = mediaServer.getRtmpPort(); schemaForUri = schema; @@ -435,10 +461,11 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { streamProxy.getStream()); } MediaInfo mediaInfo = getMediaInfo(mediaServer, streamProxy.getApp(), streamProxy.getStream()); + if (mediaInfo != null) { - if (mediaInfo.getOriginUrl().equals(streamProxy.getSrcUrl())) { + if (mediaInfo.getOriginUrl() != null && mediaInfo.getOriginUrl().equals(streamProxy.getSrcUrl())) { log.info("[启动拉流代理] 已存在, 直接返回, app: {}, stream: {}", mediaInfo.getApp(), streamProxy.getStream()); - return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), null, null, true); + return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), mediaInfo, null, true); } closeStreams(mediaServer, streamProxy.getApp(), streamProxy.getStream()); } @@ -464,8 +491,14 @@ public class ZLMMediaNodeServerService implements IMediaNodeServerService { if (data == null) { throw new ControllerException(jsonObject.getInteger("code"), "代理结果异常: " + jsonObject); }else { - streamProxy.setStreamKey(jsonObject.getString("key")); - return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), null, null, true); + streamProxy.setStreamKey(data.getString("key")); + // 由于此时流未注册,手动拼装流信息 + mediaInfo = new MediaInfo(); + mediaInfo.setApp(streamProxy.getApp()); + mediaInfo.setStream(streamProxy.getStream()); + mediaInfo.setOriginType(4); + mediaInfo.setOriginTypeStr("pull"); + return getStreamInfoByAppAndStream(mediaServer, streamProxy.getApp(), streamProxy.getStream(), mediaInfo, null, true); } } } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java index 8e793e3c9..5ed378ee6 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/OnStreamChangedHookParam.java @@ -1,6 +1,8 @@ package com.genersoft.iot.vmp.media.zlm.dto.hook; import com.genersoft.iot.vmp.vmanager.bean.StreamContent; +import lombok.Data; +import lombok.EqualsAndHashCode; import java.util.List; import java.util.Map; @@ -8,6 +10,8 @@ import java.util.Map; /** * @author lin */ +@EqualsAndHashCode(callSuper = true) +@Data public class OnStreamChangedHookParam extends HookParam{ /** @@ -109,19 +113,12 @@ public class OnStreamChangedHookParam extends HookParam{ */ private Map paramMap; - public boolean isRegist() { - return regist; - } - - public void setRegist(boolean regist) { - this.regist = regist; - } - /** * 是否是docker部署, docker部署不会自动更新zlm使用的端口,需要自己手动修改 */ private boolean docker; + @Data public static class MediaTrack { /** * 音频通道数 @@ -197,128 +194,9 @@ public class OnStreamChangedHookParam extends HookParam{ * 丢帧率 */ private float loss; - - public int getChannels() { - return channels; - } - - public void setChannels(int channels) { - this.channels = channels; - } - - public int getCodec_id() { - return codec_id; - } - - public void setCodec_id(int codec_id) { - this.codec_id = codec_id; - } - - public String getCodec_id_name() { - return codec_id_name; - } - - public void setCodec_id_name(String codec_id_name) { - this.codec_id_name = codec_id_name; - } - - public int getCodec_type() { - return codec_type; - } - - public void setCodec_type(int codec_type) { - this.codec_type = codec_type; - } - - public boolean isReady() { - return ready; - } - - public void setReady(boolean ready) { - this.ready = ready; - } - - public int getSample_bit() { - return sample_bit; - } - - public void setSample_bit(int sample_bit) { - this.sample_bit = sample_bit; - } - - public int getSample_rate() { - return sample_rate; - } - - public void setSample_rate(int sample_rate) { - this.sample_rate = sample_rate; - } - - public float getFps() { - return fps; - } - - public void setFps(float fps) { - this.fps = fps; - } - - public int getHeight() { - return height; - } - - public void setHeight(int height) { - this.height = height; - } - - public int getWidth() { - return width; - } - - public void setWidth(int width) { - this.width = width; - } - - public int getFrames() { - return frames; - } - - public void setFrames(int frames) { - this.frames = frames; - } - - public int getKey_frames() { - return key_frames; - } - - public void setKey_frames(int key_frames) { - this.key_frames = key_frames; - } - - public int getGop_size() { - return gop_size; - } - - public void setGop_size(int gop_size) { - this.gop_size = gop_size; - } - - public int getGop_interval_ms() { - return gop_interval_ms; - } - - public void setGop_interval_ms(int gop_interval_ms) { - this.gop_interval_ms = gop_interval_ms; - } - - public float getLoss() { - return loss; - } - - public void setLoss(float loss) { - this.loss = loss; - } } + @Data public static class OriginSock{ private String identifier; private String local_ip; @@ -326,204 +204,10 @@ public class OnStreamChangedHookParam extends HookParam{ private String peer_ip; private int peer_port; - public String getIdentifier() { - return identifier; - } - - public void setIdentifier(String identifier) { - this.identifier = identifier; - } - - public String getLocal_ip() { - return local_ip; - } - - public void setLocal_ip(String local_ip) { - this.local_ip = local_ip; - } - - public int getLocal_port() { - return local_port; - } - - public void setLocal_port(int local_port) { - this.local_port = local_port; - } - - public String getPeer_ip() { - return peer_ip; - } - - public void setPeer_ip(String peer_ip) { - this.peer_ip = peer_ip; - } - - public int getPeer_port() { - return peer_port; - } - - public void setPeer_port(int peer_port) { - this.peer_port = peer_port; - } } private StreamContent streamInfo; - public String getApp() { - return app; - } - - public void setApp(String app) { - this.app = app; - } - - public String getStream() { - return stream; - } - - public void setStream(String stream) { - this.stream = stream; - } - - public int getTotalReaderCount() { - return totalReaderCount; - } - - public void setTotalReaderCount(int totalReaderCount) { - this.totalReaderCount = totalReaderCount; - } - - - public int getOriginType() { - return originType; - } - - public void setOriginType(int originType) { - this.originType = originType; - } - - - public String getOriginTypeStr() { - return originTypeStr; - } - - public void setOriginTypeStr(String originTypeStr) { - this.originTypeStr = originTypeStr; - } - - public String getOriginUrl() { - return originUrl; - } - - public void setOriginUrl(String originUrl) { - this.originUrl = originUrl; - } - - public Long getCreateStamp() { - return createStamp; - } - - public void setCreateStamp(Long createStamp) { - this.createStamp = createStamp; - } - - public Long getAliveSecond() { - return aliveSecond; - } - - public void setAliveSecond(Long aliveSecond) { - this.aliveSecond = aliveSecond; - } - - public List getTracks() { - return tracks; - } - - public void setTracks(List tracks) { - this.tracks = tracks; - } - - public String getSchema() { - return schema; - } - - public void setSchema(String schema) { - this.schema = schema; - } - - public void setOriginSock(OriginSock originSock) { - this.originSock = originSock; - } - - public Long getBytesSpeed() { - return bytesSpeed; - } - - public void setBytesSpeed(Long bytesSpeed) { - this.bytesSpeed = bytesSpeed; - } - - public String getVhost() { - return vhost; - } - - public void setVhost(String vhost) { - this.vhost = vhost; - } - - public OriginSock getOriginSock() { - return originSock; - } - - public boolean isDocker() { - return docker; - } - - public void setDocker(boolean docker) { - this.docker = docker; - } - - public StreamContent getStreamInfo() { - return streamInfo; - } - - public void setStreamInfo(StreamContent streamInfo) { - this.streamInfo = streamInfo; - } - - public String getSeverId() { - return severId; - } - - public void setSeverId(String severId) { - this.severId = severId; - } - - public String getCallId() { - return callId; - } - - public void setCallId(String callId) { - this.callId = callId; - } - - - public Map getParamMap() { - return paramMap; - } - - public void setParamMap(Map paramMap) { - this.paramMap = paramMap; - } - - public String getParams() { - return params; - } - - public void setParams(String params) { - this.params = params; - } - @Override public String toString() { return "OnStreamChangedHookParam{" + diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java index 3716d73ee..33fd03648 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/CloudRecordItem.java @@ -2,12 +2,14 @@ package com.genersoft.iot.vmp.service.bean; import com.genersoft.iot.vmp.media.event.media.MediaRecordMp4Event; import com.genersoft.iot.vmp.utils.MediaServerUtils; +import lombok.Data; import java.util.Map; /** * 云端录像数据 */ +@Data public class CloudRecordItem { /** * 主键 @@ -79,6 +81,11 @@ public class CloudRecordItem { */ private long timeLen; + /** + * 所属服务ID + */ + private String serverId; + public static CloudRecordItem getInstance(MediaRecordMp4Event param) { CloudRecordItem cloudRecordItem = new CloudRecordItem(); cloudRecordItem.setApp(param.getApp()); @@ -98,115 +105,4 @@ public class CloudRecordItem { return cloudRecordItem; } - public int getId() { - return id; - } - - public void setId(int id) { - this.id = id; - } - - public String getApp() { - return app; - } - - public void setApp(String app) { - this.app = app; - } - - public String getStream() { - return stream; - } - - public void setStream(String stream) { - this.stream = stream; - } - - public String getCallId() { - return callId; - } - - public void setCallId(String callId) { - this.callId = callId; - } - - public long getStartTime() { - return startTime; - } - - public void setStartTime(long startTime) { - this.startTime = startTime; - } - - public long getEndTime() { - return endTime; - } - - public void setEndTime(long endTime) { - this.endTime = endTime; - } - - public String getMediaServerId() { - return mediaServerId; - } - - public void setMediaServerId(String mediaServerId) { - this.mediaServerId = mediaServerId; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public String getFilePath() { - return filePath; - } - - public void setFilePath(String filePath) { - this.filePath = filePath; - } - - public String getFolder() { - return folder; - } - - public void setFolder(String folder) { - this.folder = folder; - } - - public long getFileSize() { - return fileSize; - } - - public void setFileSize(long fileSize) { - this.fileSize = fileSize; - } - - public long getTimeLen() { - return timeLen; - } - - public void setTimeLen(long timeLen) { - this.timeLen = timeLen; - } - - public Boolean getCollect() { - return collect; - } - - public void setCollect(Boolean collect) { - this.collect = collect; - } - - public Boolean getReserve() { - return reserve; - } - - public void setReserve(Boolean reserve) { - this.reserve = reserve; - } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java b/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java index ac0e2b3b6..c35ceb550 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java +++ b/src/main/java/com/genersoft/iot/vmp/service/bean/SSRCInfo.java @@ -7,12 +7,14 @@ public class SSRCInfo { private int port; private String ssrc; + private String app; private String Stream; private String timeOutTaskKey; - public SSRCInfo(int port, String ssrc, String stream, String timeOutTaskKey) { + public SSRCInfo(int port, String ssrc, String app, String stream, String timeOutTaskKey) { this.port = port; this.ssrc = ssrc; + this.app = app; this.Stream = stream; this.timeOutTaskKey = timeOutTaskKey; } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java index 725115fcd..5523bd3c0 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/CloudRecordServiceImpl.java @@ -2,7 +2,7 @@ package com.genersoft.iot.vmp.service.impl; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; -import com.baomidou.dynamic.datasource.annotation.DS; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.service.ICloudRecordService; import com.genersoft.iot.vmp.media.bean.MediaServer; @@ -12,6 +12,7 @@ import com.genersoft.iot.vmp.media.zlm.AssistRESTfulUtils; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.service.bean.CloudRecordItem; import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.storager.dao.CloudRecordServiceMapper; import com.genersoft.iot.vmp.utils.CloudRecordUtils; @@ -36,7 +37,6 @@ import java.util.Set; @Slf4j @Service -@DS("share") public class CloudRecordServiceImpl implements ICloudRecordService { @Autowired @@ -51,8 +51,15 @@ public class CloudRecordServiceImpl implements ICloudRecordService { @Autowired private AssistRESTfulUtils assistRESTfulUtils; + @Autowired + private UserSetting userSetting; + + @Autowired + private IRedisRpcPlayService redisRpcPlayService; + @Override - public PageInfo getList(int page, int count, String query, String app, String stream, String startTime, String endTime, List mediaServerItems, String callId) { + public PageInfo getList(int page, int count, String query, String app, String stream, String startTime, + String endTime, List mediaServerItems, String callId) { // 开始时间和结束时间在数据库中都是以秒为单位的 Long startTimeStamp = null; Long endTimeStamp = null; @@ -109,6 +116,7 @@ public class CloudRecordServiceImpl implements ICloudRecordService { @EventListener public void onApplicationEvent(MediaRecordMp4Event event) { CloudRecordItem cloudRecordItem = CloudRecordItem.getInstance(event); + cloudRecordItem.setServerId(userSetting.getServerId()); if (ObjectUtils.isEmpty(cloudRecordItem.getCallId())) { StreamAuthorityInfo streamAuthorityInfo = redisCatchStorage.getStreamAuthorityInfo(event.getApp(), event.getStream()); if (streamAuthorityInfo != null) { @@ -237,6 +245,9 @@ public class CloudRecordServiceImpl implements ICloudRecordService { if (recordItem == null) { throw new ControllerException(ErrorCode.ERROR400.getCode(), "资源不存在"); } + if (!userSetting.getServerId().equals(recordItem.getServerId())) { + return redisRpcPlayService.getRecordPlayUrl(recordItem.getServerId(), recordId); + } String filePath = recordItem.getFilePath(); MediaServer mediaServerItem = mediaServerService.getOne(recordItem.getMediaServerId()); return CloudRecordUtils.getDownloadFilePath(mediaServerItem, filePath); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java index 3aad00353..47ca3ac55 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/LogServiceImpl.java @@ -24,7 +24,7 @@ public class LogServiceImpl implements ILogService { @Override public List queryList(String query, String startTime, String endTime) { File logFile = getLogDir(); - if (logFile == null && !logFile.exists()) { + if (logFile == null || !logFile.exists()) { throw new ControllerException(ErrorCode.ERROR100.getCode(), "获取日志文件目录失败"); } File[] files = logFile.listFiles(); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java index 05142b9ed..65e9f21cb 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java @@ -147,17 +147,17 @@ public class MediaServiceImpl implements IMediaService { ResultForOnPublish result = new ResultForOnPublish(); result.setEnable_audio(true); - // 是否录像 - if ("rtp".equals(app)) { - result.setEnable_mp4(userSetting.getRecordSip()); - } else { - result.setEnable_mp4(userSetting.getRecordPushLive()); - } // 国标流 if ("rtp".equals(app)) { InviteInfo inviteInfo = inviteStreamService.getInviteInfoByStream(null, stream); + if (inviteInfo != null) { + result.setEnable_mp4(inviteInfo.getRecord()); + }else { + result.setEnable_mp4(userSetting.getRecordSip()); + } + // 单端口模式下修改流 ID if (!mediaServer.isRtpEnable() && inviteInfo == null) { String ssrc = String.format("%010d", Long.parseLong(stream, 16)); @@ -170,7 +170,7 @@ public class MediaServiceImpl implements IMediaService { } // 设置音频信息及录制信息 - SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(stream); + SsrcTransaction ssrcTransaction = sessionManager.getSsrcTransactionByStream(app, stream); if (ssrcTransaction != null ) { // 为录制国标模拟一个鉴权信息, 方便后续写入录像文件时使用 @@ -191,9 +191,9 @@ public class MediaServiceImpl implements IMediaService { if (ssrcTransaction.getType() == InviteSessionType.DOWNLOAD) { // 获取录像的总时长,然后设置为这个视频的时长 InviteInfo inviteInfoForDownload = inviteStreamService.getInviteInfo(InviteSessionType.DOWNLOAD, channelId, stream); - if (inviteInfoForDownload != null && inviteInfoForDownload.getStreamInfo() != null) { - String startTime = inviteInfoForDownload.getStreamInfo().getStartTime(); - String endTime = inviteInfoForDownload.getStreamInfo().getEndTime(); + if (inviteInfoForDownload != null) { + String startTime = inviteInfoForDownload.getStartTime(); + String endTime = inviteInfoForDownload.getEndTime(); long difference = DateUtil.getDifference(startTime, endTime) / 1000; result.setMp4_max_second((int) difference); result.setEnable_mp4(true); @@ -208,8 +208,12 @@ public class MediaServiceImpl implements IMediaService { } } else if (app.equals("broadcast")) { result.setEnable_audio(true); + result.setEnable_mp4(userSetting.getRecordSip()); } else if (app.equals("talk")) { result.setEnable_audio(true); + result.setEnable_mp4(userSetting.getRecordSip()); + }else { + result.setEnable_mp4(userSetting.getRecordPushLive()); } if (app.equalsIgnoreCase("rtp")) { String receiveKey = VideoManagerConstants.WVP_OTHER_RECEIVE_RTP_INFO + userSetting.getServerId() + "_" + stream; diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java index ca55b4d3a..d0897839b 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java @@ -66,7 +66,7 @@ public class RecordPlanServiceImpl implements IRecordPlanService { return; } // 开启点播, - channelPlayService.play(channel, null, ((code, msg, streamInfo) -> { + channelPlayService.play(channel, null, true, ((code, msg, streamInfo) -> { if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) { log.info("[录像] 流离开时拉起需要录像的流, 开启成功, 通道ID: {}", channel.getGbId()); recordStreamMap.put(channel.getGbId(), streamInfo); @@ -79,7 +79,6 @@ public class RecordPlanServiceImpl implements IRecordPlanService { Map recordStreamMap = new HashMap<>(); -// @Scheduled(cron = "0 */30 * * * *") @Scheduled(fixedRate = 10, timeUnit = TimeUnit.MINUTES) public void execution() { log.info("[录制计划] 执行"); @@ -89,7 +88,8 @@ public class RecordPlanServiceImpl implements IRecordPlanService { if (startChannelIdList.isEmpty()) { // 当前没有录像任务, 如果存在旧的正在录像的就移除 if(!recordStreamMap.isEmpty()) { - stopStreams(recordStreamMap.keySet(), recordStreamMap); + Set recordStreamSet = new HashSet<>(recordStreamMap.keySet()); + stopStreams(recordStreamSet, recordStreamMap); recordStreamMap.clear(); } }else { @@ -110,7 +110,7 @@ public class RecordPlanServiceImpl implements IRecordPlanService { // 查找是否已经开启录像, 如果没有则开启录像 for (CommonGBChannel channel : channelList) { // 开启点播, - channelPlayService.play(channel, null, ((code, msg, streamInfo) -> { + channelPlayService.play(channel, null, true, ((code, msg, streamInfo) -> { if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) { log.info("[录像] 开启成功, 通道ID: {}", channel.getGbId()); recordStreamMap.put(channel.getGbId(), streamInfo); @@ -266,14 +266,14 @@ public class RecordPlanServiceImpl implements IRecordPlanService { } @Override - public PageInfo queryChannelList(int page, int count, String query, Integer channelType, Boolean online, Integer planId, Boolean hasLink) { + public PageInfo queryChannelList(int page, int count, String query, Integer dataType, Boolean online, Integer planId, Boolean hasLink) { PageHelper.startPage(page, count); if (query != null) { query = query.replaceAll("/", "//") .replaceAll("%", "/%") .replaceAll("_", "/_"); } - List all = channelMapper.queryForRecordPlanForWebList(planId, query, channelType, online, hasLink); + List all = channelMapper.queryForRecordPlanForWebList(planId, query, dataType, online, hasLink); return new PageInfo<>(all); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java index f12c3cb8f..d31bbcefb 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RoleServerImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.service.IRoleService; import com.genersoft.iot.vmp.storager.dao.RoleMapper; import com.genersoft.iot.vmp.storager.dao.dto.Role; @@ -10,7 +9,6 @@ import org.springframework.stereotype.Service; import java.util.List; @Service -@DS("master") public class RoleServerImpl implements IRoleService { @Autowired diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java index ccd7780ec..86099262d 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RtpServerServiceImpl.java @@ -117,11 +117,11 @@ public class RtpServerServiceImpl implements IReceiveRtpServerService { // 设置流超时的定时任务 String timeOutTaskKey = UUID.randomUUID().toString(); - SSRCInfo ssrcInfo = new SSRCInfo(rtpServerPort, ssrc, streamId, timeOutTaskKey); + SSRCInfo ssrcInfo = new SSRCInfo(rtpServerPort, ssrc, "rtp", streamId, timeOutTaskKey); OpenRTPServerResult openRTPServerResult = new OpenRTPServerResult(); openRTPServerResult.setSsrcInfo(ssrcInfo); - Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, "rtp", streamId, rtpServerParam.getMediaServerItem().getId()); + Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, ssrcInfo.getApp(), streamId, rtpServerParam.getMediaServerItem().getId()); dynamicTask.startDelay(timeOutTaskKey, () -> { // 收流超时 // 释放ssrc diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/UserApiKeyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/UserApiKeyServiceImpl.java index 85ee4f0f5..8c552b10f 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/UserApiKeyServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/UserApiKeyServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.service.IUserApiKeyService; import com.genersoft.iot.vmp.storager.dao.UserApiKeyMapper; import com.genersoft.iot.vmp.storager.dao.dto.UserApiKey; @@ -15,7 +14,6 @@ import org.springframework.stereotype.Service; import java.util.List; @Service -@DS("master") public class UserApiKeyServiceImpl implements IUserApiKeyService { @Autowired diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java index fb97db939..cf0bea20f 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java @@ -1,6 +1,5 @@ package com.genersoft.iot.vmp.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.service.IUserService; import com.genersoft.iot.vmp.storager.dao.UserMapper; import com.genersoft.iot.vmp.storager.dao.dto.User; @@ -13,7 +12,6 @@ import org.springframework.util.DigestUtils; import java.util.List; @Service -@DS("master") public class UserServiceImpl implements IUserService { @Autowired diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java new file mode 100644 index 000000000..174fa6b67 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcPlayService.java @@ -0,0 +1,39 @@ +package com.genersoft.iot.vmp.service.redisMsg; + +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; + +public interface IRedisRpcPlayService { + + + void play(String serverId, Integer channelId, ErrorCallback callback); + + void stop(String serverId, InviteSessionType type, int channelId, String stream); + + void playback(String serverId, Integer channelId, String startTime, String endTime, ErrorCallback callback); + + void download(String serverId, Integer channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback callback); + + void queryRecordInfo(String serverId, Integer channelId, String startTime, String endTime, ErrorCallback callback); + + void pauseRtp(String serverId, String streamId); + + void resumeRtp(String serverId, String streamId); + + String frontEndCommand(String serverId, Integer channelId, int cmdCode, int parameter1, int parameter2, int combindCode2); + + void playPush(Integer id, ErrorCallback callback); + + StreamInfo playProxy(String serverId, int id); + + void stopProxy(String serverId, int id); + + DownloadFileInfo getRecordPlayUrl(String serverId, Integer recordId); + + + AudioBroadcastResult audioBroadcast(String serverId, String deviceId, String channelDeviceId, Boolean broadcastMode); +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcService.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcService.java index 7e23e2767..549af39b7 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/IRedisRpcService.java @@ -2,7 +2,8 @@ package com.genersoft.iot.vmp.service.redisMsg; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.StreamInfo; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.vmanager.bean.WVPResult; public interface IRedisRpcService { @@ -23,4 +24,44 @@ public interface IRedisRpcService { long onStreamOnlineEvent(String app, String stream, CommonCallback callback); void unPushStreamOnlineEvent(String app, String stream); + + void subscribeCatalog(int id, int cycle); + + void subscribeMobilePosition(int id, int cycle, int interval); + + boolean updatePlatform(String serverId, Platform platform); + + void catalogEventPublish(String serverId, CatalogEvent catalogEvent); + + WVPResult devicesSync(String serverId, String deviceId); + + SyncStatus getChannelSyncStatus(String serverId, String deviceId); + + WVPResult deviceBasicConfig(String serverId, Device device, BasicParam basicParam); + + WVPResult deviceConfigQuery(String serverId, Device device, String channelId, String configType); + + void teleboot(String serverId, Device device); + + WVPResult recordControl(String serverId, Device device, String channelId, String recordCmdStr); + + WVPResult guard(String serverId, Device device, String guardCmdStr); + + WVPResult resetAlarm(String serverId, Device device, String channelId, String alarmMethod, String alarmType); + + void iFrame(String serverId, Device device, String channelId); + + WVPResult homePosition(String serverId, Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex); + + void dragZoomIn(String serverId, Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy); + + void dragZoomOut(String serverId, Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy); + + WVPResult deviceStatus(String serverId, Device device); + + WVPResult alarm(String serverId, Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime); + + WVPResult deviceInfo(String serverId, Device device); + + WVPResult queryPreset(String serverId, Device device, String channelId); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java index d4f65e138..886cd88eb 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/RedisAlarmMsgListener.java @@ -105,7 +105,7 @@ public class RedisAlarmMsgListener implements MessageListener { if (ObjectUtils.isEmpty(gbId)) { if (userSetting.getSendToPlatformsWhenIdLost()) { // 发送给所有的上级 - List parentPlatforms = platformService.queryEnablePlatformList(); + List parentPlatforms = platformService.queryEnablePlatformList(userSetting.getServerId()); if (!parentPlatforms.isEmpty()) { for (Platform parentPlatform : parentPlatforms) { try { diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcChannelPlayController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcChannelPlayController.java new file mode 100644 index 000000000..84b444084 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcChannelPlayController.java @@ -0,0 +1,348 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.InviteMessageInfo; +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; +import com.genersoft.iot.vmp.gb28181.service.IPTZService; +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.utils.DateUtil; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.sip.message.Response; + +@Component +@Slf4j +@RedisRpcController("channel") +public class RedisRpcChannelPlayController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IGbChannelService channelService; + + @Autowired + private IGbChannelPlayService channelPlayService; + + @Autowired + private IPTZService iptzService; + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + + /** + * 点播国标设备 + */ + @RedisRpcMapping("play") + public RedisRpcResponse playChannel(RedisRpcRequest request) { + int channelId = Integer.parseInt(request.getParam().toString()); + RedisRpcResponse response = request.getResponse(); + + if (channelId <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + InviteMessageInfo inviteInfo = new InviteMessageInfo(); + inviteInfo.setSessionName("Play"); + channelPlayService.start(channel, inviteInfo, null, (code, msg, data) ->{ + if (code == InviteErrorCode.SUCCESS.getCode()) { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(data); + }else { + response.setStatusCode(code); + } + // 手动发送结果 + sendResponse(response); + }); + return null; + } + + + /** + * 点播国标设备 + */ + @RedisRpcMapping("queryRecordInfo") + public RedisRpcResponse queryRecordInfo(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int channelId = paramJson.getIntValue("channelId"); + String startTime = paramJson.getString("startTime"); + String endTime = paramJson.getString("endTime"); + RedisRpcResponse response = request.getResponse(); + + if (channelId <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + try { + channelService.queryRecordInfo(channel, startTime, endTime, (code, msg, data) ->{ + if (code == InviteErrorCode.SUCCESS.getCode()) { + response.setStatusCode(code); + response.setBody(data); + }else { + response.setStatusCode(code); + } + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(ErrorCode.ERROR100.getCode()); + response.setBody(e.getMessage()); + } + + return null; + } + + /** + * 暂停录像回放 + */ + @RedisRpcMapping("pauseRtp") + public RedisRpcResponse pauseRtp(RedisRpcRequest request) { + String streamId = request.getParam().toString(); + RedisRpcResponse response = request.getResponse(); + + if (streamId == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + try { + channelPlayService.pauseRtp(streamId); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + }catch (ControllerException e) { + response.setStatusCode(ErrorCode.ERROR100.getCode()); + response.setBody(e.getMessage()); + } + + return response; + } + + /** + * 恢复录像回放 + */ + @RedisRpcMapping("resumeRtp") + public RedisRpcResponse resumeRtp(RedisRpcRequest request) { + String streamId = request.getParam().toString(); + RedisRpcResponse response = request.getResponse(); + + if (streamId == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + try { + channelPlayService.resumeRtp(streamId); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + }catch (ControllerException e) { + response.setStatusCode(ErrorCode.ERROR100.getCode()); + response.setBody(e.getMessage()); + } + + return response; + } + + + /** + * 停止点播国标设备 + */ + @RedisRpcMapping("stop") + public RedisRpcResponse stop(RedisRpcRequest request) { + JSONObject jsonObject = JSONObject.parseObject(request.getParam().toString()); + + RedisRpcResponse response = request.getResponse(); + + Integer channelId = jsonObject.getIntValue("channelId"); + if (channelId == null || channelId <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + String stream = jsonObject.getString("stream"); + InviteSessionType type = jsonObject.getObject("inviteSessionType", InviteSessionType.class); + + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + channelPlayService.stopPlay(type, channel, stream); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + }catch (Exception e){ + response.setStatusCode(Response.SERVER_INTERNAL_ERROR); + response.setBody(e.getMessage()); + } + return response; + } + + /** + * 录像回放国标设备 + */ + @RedisRpcMapping("playback") + public RedisRpcResponse playbackChannel(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int channelId = paramJson.getIntValue("channelId"); + String startTime = paramJson.getString("startTime"); + String endTime = paramJson.getString("endTime"); + RedisRpcResponse response = request.getResponse(); + + if (channelId <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + InviteMessageInfo inviteInfo = new InviteMessageInfo(); + inviteInfo.setSessionName("Playback"); + inviteInfo.setStartTime(DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)); + inviteInfo.setStopTime(DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime)); + channelPlayService.start(channel, inviteInfo, null, (code, msg, data) ->{ + if (code == InviteErrorCode.SUCCESS.getCode()) { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(data); + }else { + response.setStatusCode(code); + } + // 手动发送结果 + sendResponse(response); + }); + return null; + } + + /** + * 录像回放国标设备 + */ + @RedisRpcMapping("download") + public RedisRpcResponse downloadChannel(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int channelId = paramJson.getIntValue("channelId"); + String startTime = paramJson.getString("startTime"); + String endTime = paramJson.getString("endTime"); + int downloadSpeed = paramJson.getIntValue("downloadSpeed"); + RedisRpcResponse response = request.getResponse(); + + if (channelId <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + + InviteMessageInfo inviteInfo = new InviteMessageInfo(); + inviteInfo.setSessionName("Download"); + inviteInfo.setStartTime(DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(startTime)); + inviteInfo.setStopTime(DateUtil.yyyy_MM_dd_HH_mm_ssToTimestamp(endTime)); + inviteInfo.setDownloadSpeed(downloadSpeed + ""); + channelPlayService.start(channel, inviteInfo, null, (code, msg, data) ->{ + if (code == InviteErrorCode.SUCCESS.getCode()) { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(data); + }else { + response.setStatusCode(code); + } + // 手动发送结果 + sendResponse(response); + }); + return null; + } + + /** + * 云台控制 + */ + @RedisRpcMapping("ptz/frontEndCommand") + public RedisRpcResponse frontEndCommand(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int channelId = paramJson.getIntValue("channelId"); + int cmdCode = paramJson.getIntValue("cmdCode"); + int parameter1 = paramJson.getIntValue("parameter1"); + int parameter2 = paramJson.getIntValue("parameter2"); + int combindCode2 = paramJson.getIntValue("combindCode2"); + + RedisRpcResponse response = request.getResponse(); + + if (channelId <= 0 || cmdCode < 0 || parameter1 < 0 || parameter2 < 0 || combindCode2 < 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + // 获取对应的设备和通道信息 + CommonGBChannel channel = channelService.getOne(channelId); + if (channel == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + iptzService.frontEndCommand(channel, cmdCode, parameter1, parameter2, combindCode2); + }catch (ControllerException e) { + response.setStatusCode(ErrorCode.ERROR100.getCode()); + response.setBody(e.getMessage()); + return response; + } + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcCloudRecordController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcCloudRecordController.java new file mode 100644 index 000000000..516f5bfb4 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcCloudRecordController.java @@ -0,0 +1,66 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.service.ICloudRecordService; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RedisRpcController("cloudRecord") +public class RedisRpcCloudRecordController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private ICloudRecordService cloudRecordService; + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + /** + * 播放 + */ + @RedisRpcMapping("play") + public RedisRpcResponse play(RedisRpcRequest request) { + int id = Integer.parseInt(request.getParam().toString()); + RedisRpcResponse response = request.getResponse(); + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + DownloadFileInfo downloadFileInfo = cloudRecordService.getPlayUrlPath(id); + if (downloadFileInfo == null) { + response.setStatusCode(ErrorCode.ERROR100.getCode()); + response.setBody("get play url error"); + return response; + } + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(downloadFileInfo)); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDeviceController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDeviceController.java new file mode 100644 index 000000000..a6d727e1f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDeviceController.java @@ -0,0 +1,498 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.BasicParam; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.SyncStatus; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RedisRpcController("device") +public class RedisRpcDeviceController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IDeviceService deviceService; + + @Autowired + private IStreamProxyService streamProxyService; + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + /** + * 通道同步 + */ + @RedisRpcMapping("devicesSync") + public RedisRpcResponse devicesSync(RedisRpcRequest request) { + String deviceId = request.getParam().toString(); + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + WVPResult result = deviceService.devicesSync(device); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(result)); + return response; + } + + /** + * 获取通道同步状态 + */ + @RedisRpcMapping("getChannelSyncStatus") + public RedisRpcResponse getChannelSyncStatus(RedisRpcRequest request) { + String deviceId = request.getParam().toString(); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + SyncStatus channelSyncStatus = deviceService.getChannelSyncStatus(deviceId); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(channelSyncStatus)); + return response; + } + + @RedisRpcMapping("deviceBasicConfig") + public RedisRpcResponse deviceBasicConfig(RedisRpcRequest request) { + BasicParam basicParam = JSONObject.parseObject(request.getParam().toString(), BasicParam.class); + + Device device = deviceService.getDeviceByDeviceId(basicParam.getDeviceId()); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + deviceService.deviceBasicConfig(device, basicParam, (code, msg, data) -> { + response.setStatusCode(code); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + return null; + } + + @RedisRpcMapping("deviceConfigQuery") + public RedisRpcResponse deviceConfigQuery(RedisRpcRequest request) { + + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + String configType = paramJson.getString("configType"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + deviceService.deviceConfigQuery(device, channelId, configType, (code, msg, data) -> { + response.setStatusCode(code); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + return null; + } + + @RedisRpcMapping("teleboot") + public RedisRpcResponse teleboot(RedisRpcRequest request) { + String deviceId = request.getParam().toString(); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.teleboot(device); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + return response; + } + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(WVPResult.success()); + return response; + } + + @RedisRpcMapping("record") + public RedisRpcResponse record(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + String recordCmdStr = paramJson.getString("recordCmdStr"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.record(device, channelId, recordCmdStr, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("guard") + public RedisRpcResponse guard(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String guardCmdStr = paramJson.getString("guardCmdStr"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.guard(device, guardCmdStr, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("resetAlarm") + public RedisRpcResponse resetAlarm(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + String alarmMethod = paramJson.getString("alarmMethod"); + String alarmType = paramJson.getString("alarmType"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.resetAlarm(device, channelId, alarmMethod, alarmType, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("iFrame") + public RedisRpcResponse iFrame(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.iFrame(device, channelId); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("homePosition") + public RedisRpcResponse homePosition(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + + Boolean enabled = paramJson.getBoolean("enabled"); + Integer resetTime = paramJson.getInteger("resetTime"); + Integer presetIndex = paramJson.getInteger("presetIndex"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.homePosition(device, channelId, enabled, resetTime, presetIndex, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("dragZoomIn") + public RedisRpcResponse dragZoomIn(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + Integer length = paramJson.getInteger("length"); + Integer width = paramJson.getInteger("width"); + Integer midpointx = paramJson.getInteger("midpointx"); + Integer midpointy = paramJson.getInteger("midpointy"); + Integer lengthx = paramJson.getInteger("lengthx"); + Integer lengthy = paramJson.getInteger("lengthy"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.dragZoomIn(device, channelId, length, width, midpointx, midpointy, lengthx, lengthy, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("dragZoomOut") + public RedisRpcResponse dragZoomOut(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + Integer length = paramJson.getInteger("length"); + Integer width = paramJson.getInteger("width"); + Integer midpointx = paramJson.getInteger("midpointx"); + Integer midpointy = paramJson.getInteger("midpointy"); + Integer lengthx = paramJson.getInteger("lengthx"); + Integer lengthy = paramJson.getInteger("lengthy"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.dragZoomOut(device, channelId, length, width, midpointx, midpointy, lengthx, lengthy, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("alarm") + public RedisRpcResponse alarm(RedisRpcRequest request) { + + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String startPriority = paramJson.getString("startPriority"); + String endPriority = paramJson.getString("endPriority"); + String alarmMethod = paramJson.getString("alarmMethod"); + String alarmType = paramJson.getString("alarmType"); + String startTime = paramJson.getString("startTime"); + String endTime = paramJson.getString("endTime"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.alarm(device, startPriority, endPriority, alarmMethod, alarmType, startTime, endTime, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("deviceStatus") + public RedisRpcResponse deviceStatus(RedisRpcRequest request) { + String deviceId = request.getParam().toString(); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.deviceStatus(device, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("info") + public RedisRpcResponse info(RedisRpcRequest request) { + String deviceId = request.getParam().toString(); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.deviceInfo(device, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + @RedisRpcMapping("info") + public RedisRpcResponse queryPreset(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelId = paramJson.getString("channelId"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + try { + deviceService.queryPreset(device, channelId, (code, msg, data) -> { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(new WVPResult<>(code, msg, data)); + // 手动发送结果 + sendResponse(response); + }); + }catch (ControllerException e) { + response.setStatusCode(e.getCode()); + response.setBody(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMsg())); + sendResponse(response); + } + return null; + } + + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDevicePlayController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDevicePlayController.java new file mode 100644 index 000000000..2e83cc71f --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcDevicePlayController.java @@ -0,0 +1,74 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IPlayService; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RedisRpcController("devicePlay") +public class RedisRpcDevicePlayController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IDeviceService deviceService; + + @Autowired + private IPlayService playService; + + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + /** + * 获取通道同步状态 + */ + @RedisRpcMapping("audioBroadcast") + public RedisRpcResponse audioBroadcast(RedisRpcRequest request) { + JSONObject paramJson = JSON.parseObject(request.getParam().toString()); + String deviceId = paramJson.getString("deviceId"); + String channelDeviceId = paramJson.getString("channelDeviceId"); + Boolean broadcastMode = paramJson.getBoolean("broadcastMode"); + + Device device = deviceService.getDeviceByDeviceId(deviceId); + + RedisRpcResponse response = request.getResponse(); + if (device == null || !userSetting.getServerId().equals(device.getServerId())) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + AudioBroadcastResult audioBroadcastResult = playService.audioBroadcast(deviceId, channelDeviceId, broadcastMode); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(audioBroadcastResult)); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcGbDeviceController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcGbDeviceController.java new file mode 100644 index 000000000..798c938c7 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcGbDeviceController.java @@ -0,0 +1,99 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.Device; +import com.genersoft.iot.vmp.gb28181.bean.InviteMessageInfo; +import com.genersoft.iot.vmp.gb28181.service.IDeviceService; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; +import com.genersoft.iot.vmp.gb28181.service.IPTZService; +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.utils.DateUtil; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import javax.sip.message.Response; + +@Component +@Slf4j +@RedisRpcController("device") +public class RedisRpcGbDeviceController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IDeviceService deviceService; + + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + + /** + * 目录订阅 + */ + @RedisRpcMapping("subscribeCatalog") + public RedisRpcResponse subscribeCatalog(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int id = paramJson.getIntValue("id"); + int cycle = paramJson.getIntValue("cycle"); + + RedisRpcResponse response = request.getResponse(); + + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + deviceService.subscribeCatalog(id, cycle); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } + + /** + * 移动位置订阅 + */ + @RedisRpcMapping("subscribeMobilePosition") + public RedisRpcResponse subscribeMobilePosition(RedisRpcRequest request) { + JSONObject paramJson = JSONObject.parseObject(request.getParam().toString()); + int id = paramJson.getIntValue("id"); + int cycle = paramJson.getIntValue("cycle"); + int interval = paramJson.getIntValue("interval"); + + RedisRpcResponse response = request.getResponse(); + + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + deviceService.subscribeMobilePosition(id, cycle, interval); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java new file mode 100644 index 000000000..c5a9f4604 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcPlatformController.java @@ -0,0 +1,83 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; +import com.genersoft.iot.vmp.gb28181.bean.Platform; +import com.genersoft.iot.vmp.gb28181.event.EventPublisher; +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; +import com.genersoft.iot.vmp.gb28181.service.IPlatformChannelService; +import com.genersoft.iot.vmp.gb28181.service.IPlatformService; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +@RedisRpcController("platform") +public class RedisRpcPlatformController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IPlatformService platformService; + + @Autowired + private IPlatformChannelService platformChannelService; + + @Autowired + private EventPublisher eventPublisher; + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + /** + * 更新 + */ + @RedisRpcMapping("update") + public RedisRpcResponse play(RedisRpcRequest request) { + Platform platform = JSONObject.parseObject(request.getParam().toString(), Platform.class); + RedisRpcResponse response = request.getResponse(); + boolean update = platformService.update(platform); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(Boolean.toString(update)); + return response; + } + + /** + * 目录更新推送 + */ + @RedisRpcMapping("catalogEventPublish") + public RedisRpcResponse catalogEventPublish(RedisRpcRequest request) { + JSONObject jsonObject = JSONObject.parseObject(request.getParam().toString()); + Platform platform = jsonObject.getObject("platform", Platform.class); + List channels = jsonObject.getJSONArray("channels").toJavaList(CommonGBChannel.class); + String type = jsonObject.getString("type"); + eventPublisher.catalogEventPublish(platform, channels, type, false); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcSendRtpController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcSendRtpController.java new file mode 100644 index 000000000..fa8180252 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcSendRtpController.java @@ -0,0 +1,165 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; +import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; +import com.genersoft.iot.vmp.media.bean.MediaInfo; +import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.service.IMediaServerService; +import com.genersoft.iot.vmp.service.ISendRtpServerService; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import com.genersoft.iot.vmp.vmanager.bean.WVPResult; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sip.message.Response; + +@Component +@Slf4j +@RedisRpcController("sendRtp") +public class RedisRpcSendRtpController extends RpcController { + + @Autowired + private SSRCFactory ssrcFactory; + + @Autowired + private IMediaServerService mediaServerService; + + @Autowired + private ISendRtpServerService sendRtpServerService; + + @Autowired + private UserSetting userSetting; + + + /** + * 获取发流的信息 + */ + @RedisRpcMapping("getSendRtpItem") + public RedisRpcResponse getSendRtpItem(RedisRpcRequest request) { + String callId = request.getParam().toString(); + SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); + if (sendRtpItem == null) { + log.info("[redis-rpc] 获取发流的信息, 未找到redis中的发流信息, callId:{}", callId); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } + log.info("[redis-rpc] 获取发流的信息: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); + // 查询本级是否有这个流 + MediaServer mediaServerItem = mediaServerService.getMediaServerByAppAndStream(sendRtpItem.getApp(), sendRtpItem.getStream()); + if (mediaServerItem == null) { + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + } + // 自平台内容 + int localPort = sendRtpServerService.getNextPort(mediaServerItem); + if (localPort == 0) { + log.info("[redis-rpc] getSendRtpItem->服务器端口资源不足" ); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + } + // 写入redis, 超时时回复 + sendRtpItem.setStatus(1); + sendRtpItem.setServerId(userSetting.getServerId()); + sendRtpItem.setLocalIp(mediaServerItem.getSdpIp()); + if (sendRtpItem.getSsrc() == null) { + // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 + String ssrc = "Play".equalsIgnoreCase(sendRtpItem.getSessionName()) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); + sendRtpItem.setSsrc(ssrc); + } + sendRtpServerService.update(sendRtpItem); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(callId); + return response; + } + + /** + * 开始发流 + */ + @RedisRpcMapping("startSendRtp") + public RedisRpcResponse startSendRtp(RedisRpcRequest request) { + String callId = request.getParam().toString(); + SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + if (sendRtpItem == null) { + log.info("[redis-rpc] 开始发流, 未找到redis中的发流信息, callId:{}", callId); + WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到redis中的发流信息"); + response.setBody(wvpResult); + return response; + } + log.info("[redis-rpc] 开始发流: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); + MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); + if (mediaServer == null) { + log.info("[redis-rpc] startSendRtp->未找到MediaServer: {}", sendRtpItem.getMediaServerId() ); + WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到MediaServer"); + response.setBody(wvpResult); + return response; + } + MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream()); + if (mediaInfo == null) { + log.info("[redis-rpc] startSendRtp->流不在线: {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream() ); + WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "流不在线"); + response.setBody(wvpResult); + return response; + } + try { + mediaServerService.startSendRtp(mediaServer, sendRtpItem); + }catch (ControllerException exception) { + log.info("[redis-rpc] 发流失败: {}/{}, 目标地址: {}:{}, {}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), exception.getMsg()); + WVPResult wvpResult = WVPResult.fail(exception.getCode(), exception.getMsg()); + response.setBody(wvpResult); + return response; + } + log.info("[redis-rpc] 发流成功: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); + WVPResult wvpResult = WVPResult.success(); + response.setBody(wvpResult); + return response; + } + + /** + * 停止发流 + */ + @RedisRpcMapping("stopSendRtp") + public RedisRpcResponse stopSendRtp(RedisRpcRequest request) { + String callId = request.getParam().toString(); + SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); + RedisRpcResponse response = request.getResponse(); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + if (sendRtpItem == null) { + log.info("[redis-rpc] 停止推流, 未找到redis中的发流信息, key:{}", callId); + WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到redis中的发流信息"); + response.setBody(wvpResult); + return response; + } + log.info("[redis-rpc] 停止推流: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort() ); + MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); + if (mediaServer == null) { + log.info("[redis-rpc] stopSendRtp->未找到MediaServer: {}", sendRtpItem.getMediaServerId() ); + WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到MediaServer"); + response.setBody(wvpResult); + return response; + } + try { + mediaServerService.stopSendRtp(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc()); + }catch (ControllerException exception) { + log.info("[redis-rpc] 停止推流失败: {}/{}, 目标地址: {}:{}, code: {}, msg: {}", sendRtpItem.getApp(), + sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), exception.getCode(), exception.getMsg() ); + response.setBody(WVPResult.fail(exception.getCode(), exception.getMsg())); + return response; + } + log.info("[redis-rpc] 停止推流成功: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort() ); + response.setBody(WVPResult.success()); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamProxyController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamProxyController.java new file mode 100644 index 000000000..55764c531 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamProxyController.java @@ -0,0 +1,95 @@ +package com.genersoft.iot.vmp.service.redisMsg.control; + +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; +import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService; +import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyService; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +@RedisRpcController("streamProxy") +public class RedisRpcStreamProxyController extends RpcController { + + @Autowired + private UserSetting userSetting; + + @Autowired + private RedisTemplate redisTemplate; + + @Autowired + private IStreamProxyPlayService streamProxyPlayService; + + @Autowired + private IStreamProxyService streamProxyService; + + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); + } + + /** + * 播放 + */ + @RedisRpcMapping("play") + public RedisRpcResponse play(RedisRpcRequest request) { + int id = Integer.parseInt(request.getParam().toString()); + RedisRpcResponse response = request.getResponse(); + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + StreamProxy streamProxy = streamProxyService.getStreamProxy(id); + if (streamProxy == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + StreamInfo streamInfo = streamProxyPlayService.startProxy(streamProxy); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(streamInfo)); + return response; + } + + /** + * 停止 + */ + @RedisRpcMapping("stop") + public RedisRpcResponse stop(RedisRpcRequest request) { + int id = Integer.parseInt(request.getParam().toString()); + RedisRpcResponse response = request.getResponse(); + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + StreamProxy streamProxy = streamProxyService.getStreamProxy(id); + if (streamProxy == null) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); + return response; + } + streamProxyPlayService.stopProxy(streamProxy); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + return response; + } + +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java similarity index 54% rename from src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcController.java rename to src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java index b74df842f..d9fd90ed2 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcController.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/control/RedisRpcStreamPushController.java @@ -3,33 +3,32 @@ package com.genersoft.iot.vmp.service.redisMsg.control; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; -import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcMessage; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; -import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; import com.genersoft.iot.vmp.media.event.hook.HookType; import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.ISendRtpServerService; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcController; +import com.genersoft.iot.vmp.service.redisMsg.dto.RedisRpcMapping; +import com.genersoft.iot.vmp.service.redisMsg.dto.RpcController; +import com.genersoft.iot.vmp.streamPush.service.IStreamPushPlayService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; -import com.genersoft.iot.vmp.vmanager.bean.WVPResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; -/** - * 其他wvp发起的rpc调用,这里的方法被 RedisRpcConfig 通过反射寻找对应的方法名称调用 - */ -@Slf4j @Component -public class RedisRpcController { +@Slf4j +@RedisRpcController("streamPush") +public class RedisRpcStreamPushController extends RpcController { @Autowired private SSRCFactory ssrcFactory; @@ -49,52 +48,22 @@ public class RedisRpcController { @Autowired private RedisTemplate redisTemplate; + @Autowired + private IStreamPushPlayService streamPushPlayService; - /** - * 获取发流的信息 - */ - public RedisRpcResponse getSendRtpItem(RedisRpcRequest request) { - String callId = request.getParam().toString(); - SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); - if (sendRtpItem == null) { - log.info("[redis-rpc] 获取发流的信息, 未找到redis中的发流信息, callId:{}", callId); - RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - return response; - } - log.info("[redis-rpc] 获取发流的信息: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); - // 查询本级是否有这个流 - MediaServer mediaServerItem = mediaServerService.getMediaServerByAppAndStream(sendRtpItem.getApp(), sendRtpItem.getStream()); - if (mediaServerItem == null) { - RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - } - // 自平台内容 - int localPort = sendRtpServerService.getNextPort(mediaServerItem); - if (localPort == 0) { - log.info("[redis-rpc] getSendRtpItem->服务器端口资源不足" ); - RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - } - // 写入redis, 超时时回复 - sendRtpItem.setStatus(1); - sendRtpItem.setServerId(userSetting.getServerId()); - sendRtpItem.setLocalIp(mediaServerItem.getSdpIp()); - if (sendRtpItem.getSsrc() == null) { - // 上级平台点播时不使用上级平台指定的ssrc,使用自定义的ssrc,参考国标文档-点播外域设备媒体流SSRC处理方式 - String ssrc = "Play".equalsIgnoreCase(sendRtpItem.getSessionName()) ? ssrcFactory.getPlaySsrc(mediaServerItem.getId()) : ssrcFactory.getPlayBackSsrc(mediaServerItem.getId()); - sendRtpItem.setSsrc(ssrc); - } - sendRtpServerService.update(sendRtpItem); - RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - response.setBody(callId); - return response; + + private void sendResponse(RedisRpcResponse response){ + log.info("[redis-rpc] >> {}", response); + response.setToId(userSetting.getServerId()); + RedisRpcMessage message = new RedisRpcMessage(); + message.setResponse(response); + redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); } /** * 监听流上线 */ + @RedisRpcMapping("waitePushStreamOnline") public RedisRpcResponse waitePushStreamOnline(RedisRpcRequest request) { SendRtpInfo sendRtpItem = JSONObject.parseObject(request.getParam().toString(), SendRtpInfo.class); log.info("[redis-rpc] 监听流上线: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); @@ -115,7 +84,7 @@ public class RedisRpcController { sendRtpServerService.update(sendRtpItem); RedisRpcResponse response = request.getResponse(); response.setBody(sendRtpItem.getChannelId()); - response.setStatusCode(200); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); } // 监听流上线。 流上线直接发送sendRtpItem消息给实际的信令处理者 Hook hook = Hook.getInstance(HookType.on_media_arrival, sendRtpItem.getApp(), sendRtpItem.getStream(), null); @@ -134,7 +103,7 @@ public class RedisRpcController { redisTemplate.opsForValue().set(sendRtpItem.getChannelId(), sendRtpItem); RedisRpcResponse response = request.getResponse(); response.setBody(sendRtpItem.getChannelId()); - response.setStatusCode(200); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); // 手动发送结果 sendResponse(response); hookSubscribe.removeSubscribe(hook); @@ -146,6 +115,7 @@ public class RedisRpcController { /** * 监听流上线 */ + @RedisRpcMapping("onStreamOnlineEvent") public RedisRpcResponse onStreamOnlineEvent(RedisRpcRequest request) { StreamInfo streamInfo = JSONObject.parseObject(request.getParam().toString(), StreamInfo.class); log.info("[redis-rpc] 监听流信息,等待流上线: {}/{}", streamInfo.getApp(), streamInfo.getStream()); @@ -155,7 +125,7 @@ public class RedisRpcController { log.info("[redis-rpc] 监听流上线时发现流已存在直接返回: {}/{}", streamInfo.getApp(), streamInfo.getStream()); RedisRpcResponse response = request.getResponse(); response.setBody(JSONObject.toJSONString(streamInfoInServer)); - response.setStatusCode(200); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); return response; } // 监听流上线。 流上线直接发送sendRtpItem消息给实际的信令处理者 @@ -168,7 +138,7 @@ public class RedisRpcController { streamInfo.getApp(), streamInfo.getStream(), hookData.getMediaInfo(), hookData.getMediaInfo() != null ? hookData.getMediaInfo().getCallId() : null); response.setBody(JSONObject.toJSONString(streamInfoByAppAndStream)); - response.setStatusCode(200); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); // 手动发送结果 sendResponse(response); hookSubscribe.removeSubscribe(hook); @@ -179,6 +149,7 @@ public class RedisRpcController { /** * 停止监听流上线 */ + @RedisRpcMapping("stopWaitePushStreamOnline") public RedisRpcResponse stopWaitePushStreamOnline(RedisRpcRequest request) { SendRtpInfo sendRtpItem = JSONObject.parseObject(request.getParam().toString(), SendRtpInfo.class); log.info("[redis-rpc] 停止监听流上线: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort() ); @@ -186,13 +157,14 @@ public class RedisRpcController { Hook hook = Hook.getInstance(HookType.on_media_arrival, sendRtpItem.getApp(), sendRtpItem.getStream(), null); hookSubscribe.removeSubscribe(hook); RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); return response; } /** * 停止监听流上线 */ + @RedisRpcMapping("unPushStreamOnlineEvent") public RedisRpcResponse unPushStreamOnlineEvent(RedisRpcRequest request) { StreamInfo streamInfo = JSONObject.parseObject(request.getParam().toString(), StreamInfo.class); log.info("[redis-rpc] 停止监听流上线: {}/{}", streamInfo.getApp(), streamInfo.getStream()); @@ -200,94 +172,30 @@ public class RedisRpcController { Hook hook = Hook.getInstance(HookType.on_media_arrival, streamInfo.getApp(), streamInfo.getStream(), null); hookSubscribe.removeSubscribe(hook); RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - return response; - } - - - /** - * 开始发流 - */ - public RedisRpcResponse startSendRtp(RedisRpcRequest request) { - String callId = request.getParam().toString(); - SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); - RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - if (sendRtpItem == null) { - log.info("[redis-rpc] 开始发流, 未找到redis中的发流信息, callId:{}", callId); - WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到redis中的发流信息"); - response.setBody(wvpResult); - return response; - } - log.info("[redis-rpc] 开始发流: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); - MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - if (mediaServer == null) { - log.info("[redis-rpc] startSendRtp->未找到MediaServer: {}", sendRtpItem.getMediaServerId() ); - WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到MediaServer"); - response.setBody(wvpResult); - return response; - } - MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream()); - if (mediaInfo == null) { - log.info("[redis-rpc] startSendRtp->流不在线: {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream() ); - WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "流不在线"); - response.setBody(wvpResult); - return response; - } - try { - mediaServerService.startSendRtp(mediaServer, sendRtpItem); - }catch (ControllerException exception) { - log.info("[redis-rpc] 发流失败: {}/{}, 目标地址: {}:{}, {}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), exception.getMsg()); - WVPResult wvpResult = WVPResult.fail(exception.getCode(), exception.getMsg()); - response.setBody(wvpResult); - return response; - } - log.info("[redis-rpc] 发流成功: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort()); - WVPResult wvpResult = WVPResult.success(); - response.setBody(wvpResult); + response.setStatusCode(ErrorCode.SUCCESS.getCode()); return response; } /** - * 停止发流 + * 停止监听流上线 */ - public RedisRpcResponse stopSendRtp(RedisRpcRequest request) { - String callId = request.getParam().toString(); - SendRtpInfo sendRtpItem = sendRtpServerService.queryByCallId(callId); + @RedisRpcMapping("play") + public RedisRpcResponse play(RedisRpcRequest request) { + int id = Integer.parseInt(request.getParam().toString()); RedisRpcResponse response = request.getResponse(); - response.setStatusCode(200); - if (sendRtpItem == null) { - log.info("[redis-rpc] 停止推流, 未找到redis中的发流信息, key:{}", callId); - WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到redis中的发流信息"); - response.setBody(wvpResult); + if (id <= 0) { + response.setStatusCode(ErrorCode.ERROR400.getCode()); + response.setBody("param error"); return response; } - log.info("[redis-rpc] 停止推流: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort() ); - MediaServer mediaServer = mediaServerService.getOne(sendRtpItem.getMediaServerId()); - if (mediaServer == null) { - log.info("[redis-rpc] stopSendRtp->未找到MediaServer: {}", sendRtpItem.getMediaServerId() ); - WVPResult wvpResult = WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到MediaServer"); - response.setBody(wvpResult); - return response; - } - try { - mediaServerService.stopSendRtp(mediaServer, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getSsrc()); - }catch (ControllerException exception) { - log.info("[redis-rpc] 停止推流失败: {}/{}, 目标地址: {}:{}, code: {}, msg: {}", sendRtpItem.getApp(), - sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort(), exception.getCode(), exception.getMsg() ); - response.setBody(WVPResult.fail(exception.getCode(), exception.getMsg())); - return response; - } - log.info("[redis-rpc] 停止推流成功: {}/{}, 目标地址: {}:{}", sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getIp(), sendRtpItem.getPort() ); - response.setBody(WVPResult.success()); - return response; + streamPushPlayService.start(id, (code, msg, data) -> { + if (code == ErrorCode.SUCCESS.getCode()) { + response.setStatusCode(ErrorCode.SUCCESS.getCode()); + response.setBody(JSONObject.toJSONString(data)); + sendResponse(response); + } + }, null, null); + return null; } - private void sendResponse(RedisRpcResponse response){ - log.info("[redis-rpc] >> {}", response); - response.setToId(userSetting.getServerId()); - RedisRpcMessage message = new RedisRpcMessage(); - message.setResponse(response); - redisTemplate.convertAndSend(RedisRpcConfig.REDIS_REQUEST_CHANNEL_KEY, message); - } } diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcController.java new file mode 100644 index 000000000..f314b0c01 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcController.java @@ -0,0 +1,13 @@ +package com.genersoft.iot.vmp.service.redisMsg.dto; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RedisRpcController { + /** + * 请求路径 + */ + String value() default ""; +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcMapping.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcMapping.java new file mode 100644 index 000000000..61f51bb68 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RedisRpcMapping.java @@ -0,0 +1,13 @@ +package com.genersoft.iot.vmp.service.redisMsg.dto; + +import java.lang.annotation.*; + +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface RedisRpcMapping { + /** + * 请求路径 + */ + String value() default ""; +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RpcController.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RpcController.java new file mode 100644 index 000000000..4544812f5 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/dto/RpcController.java @@ -0,0 +1,33 @@ +package com.genersoft.iot.vmp.service.redisMsg.dto; + + +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcClassHandler; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.PostConstruct; +import java.lang.reflect.Method; + +public class RpcController { + + @Autowired + private RedisRpcConfig redisRpcConfig; + + + @PostConstruct + public void init() { + String controllerPath = this.getClass().getAnnotation(RedisRpcController.class).value(); + // 扫描其下的方法 + Method[] methods = this.getClass().getDeclaredMethods(); + for (Method method : methods) { + RedisRpcMapping annotation = method.getAnnotation(RedisRpcMapping.class); + if (annotation != null) { + String methodPath = annotation.value(); + if (methodPath != null) { + redisRpcConfig.addHandler(controllerPath + "/" + methodPath, new RedisRpcClassHandler(this, method)); + } + } + + } + } +} diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java new file mode 100644 index 000000000..4404a7205 --- /dev/null +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcPlayServiceImpl.java @@ -0,0 +1,257 @@ +package com.genersoft.iot.vmp.service.redisMsg.service; + +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.InviteSessionType; +import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; +import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; +import com.genersoft.iot.vmp.gb28181.bean.RecordInfo; +import com.genersoft.iot.vmp.service.bean.DownloadFileInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; +import com.genersoft.iot.vmp.vmanager.bean.AudioBroadcastResult; +import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.concurrent.TimeUnit; + +@Slf4j +@Service +public class RedisRpcPlayServiceImpl implements IRedisRpcPlayService { + + + @Autowired + private RedisRpcConfig redisRpcConfig; + + @Autowired + private UserSetting userSetting; + + + private RedisRpcRequest buildRequest(String uri, Object param) { + RedisRpcRequest request = new RedisRpcRequest(); + request.setFromId(userSetting.getServerId()); + request.setParam(param); + request.setUri(uri); + return request; + } + + @Override + public void play(String serverId, Integer channelId, ErrorCallback callback) { + RedisRpcRequest request = buildRequest("channel/play", channelId); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.MILLISECONDS); + if (response == null) { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); + }else { + if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + StreamInfo streamInfo = JSON.parseObject(response.getBody().toString(), StreamInfo.class); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + }else { + callback.run(response.getStatusCode(), response.getBody().toString(), null); + } + } + } + + @Override + public void stop(String serverId, InviteSessionType type, int channelId, String stream) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channelId", channelId); + jsonObject.put("stream", stream); + jsonObject.put("inviteSessionType", type); + RedisRpcRequest request = buildRequest("channel/stop", jsonObject.toJSONString()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MICROSECONDS); + if (response == null) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg()); + }else { + if (response.getStatusCode() != ErrorCode.SUCCESS.getCode()) { + throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg()); + } + } + } + + @Override + public void queryRecordInfo(String serverId, Integer channelId, String startTime, String endTime, ErrorCallback callback) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channelId", channelId); + jsonObject.put("startTime", startTime); + jsonObject.put("endTime", endTime); + RedisRpcRequest request = buildRequest("channel/queryRecordInfo", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getRecordInfoTimeout(), TimeUnit.MILLISECONDS); + if (response == null) { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); + }else { + if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + RecordInfo recordInfo = JSON.parseObject(response.getBody().toString(), RecordInfo.class); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), recordInfo); + }else { + callback.run(response.getStatusCode(), response.getBody().toString(), null); + } + } + } + + @Override + public void playback(String serverId, Integer channelId, String startTime, String endTime, ErrorCallback callback) { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channelId", channelId); + jsonObject.put("startTime", startTime); + jsonObject.put("endTime", endTime); + RedisRpcRequest request = buildRequest("channel/playback", jsonObject.toString()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.MILLISECONDS); + if (response == null) { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); + }else { + if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + StreamInfo streamInfo = JSON.parseObject(response.getBody().toString(), StreamInfo.class); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + }else { + callback.run(response.getStatusCode(), response.getBody().toString(), null); + } + } + } + + @Override + public void pauseRtp(String serverId, String streamId) { + RedisRpcRequest request = buildRequest("channel/pauseRtp", streamId); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 5, TimeUnit.SECONDS); + if (response == null) { + log.info("[RPC 暂停回放] 失败, streamId: {}", streamId); + }else { + if (response.getStatusCode() != ErrorCode.SUCCESS.getCode()) { + log.info("[RPC 暂停回放] 失败, {}, streamId: {}", response.getBody(), streamId); + } + } + } + + @Override + public void resumeRtp(String serverId, String streamId) { + RedisRpcRequest request = buildRequest("channel/resumeRtp", streamId); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 5, TimeUnit.SECONDS); + if (response == null) { + log.info("[RPC 恢复回放] 失败, streamId: {}", streamId); + }else { + if (response.getStatusCode() != ErrorCode.SUCCESS.getCode()) { + log.info("[RPC 恢复回放] 失败, {}, streamId: {}", response.getBody(), streamId); + } + } + } + + @Override + public void download(String serverId, Integer channelId, String startTime, String endTime, int downloadSpeed, ErrorCallback callback) { + + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channelId", channelId); + jsonObject.put("startTime", startTime); + jsonObject.put("endTime", endTime); + jsonObject.put("downloadSpeed", downloadSpeed); + RedisRpcRequest request = buildRequest("channel/download", jsonObject.toString()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.MILLISECONDS); + if (response == null) { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); + }else { + if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + StreamInfo streamInfo = JSON.parseObject(response.getBody().toString(), StreamInfo.class); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + }else { + callback.run(response.getStatusCode(), response.getBody().toString(), null); + } + } + } + + @Override + public String frontEndCommand(String serverId, Integer channelId, int cmdCode, int parameter1, int parameter2, int combindCode2) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("channelId", channelId); + jsonObject.put("cmdCode", cmdCode); + jsonObject.put("parameter1", parameter1); + jsonObject.put("parameter2", parameter2); + jsonObject.put("combindCode2", combindCode2); + RedisRpcRequest request = buildRequest("channel/ptz/frontEndCommand", jsonObject.toString()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.MILLISECONDS); + if (response == null) { + return ErrorCode.ERROR100.getMsg(); + }else { + if (response.getStatusCode() != ErrorCode.SUCCESS.getCode()) { + return response.getBody().toString(); + } + } + return null; + } + + @Override + public void playPush(Integer id, ErrorCallback callback) { + RedisRpcRequest request = buildRequest("streamPush/play", id); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); + if (response == null) { + callback.run(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg(), null); + }else { + if (response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + StreamInfo streamInfo = JSON.parseObject(response.getBody().toString(), StreamInfo.class); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + }else { + callback.run(response.getStatusCode(), response.getBody().toString(), null); + } + } + } + + @Override + public StreamInfo playProxy(String serverId, int id) { + RedisRpcRequest request = buildRequest("streamProxy/play", id); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); + if (response != null && response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + return JSON.parseObject(response.getBody().toString(), StreamInfo.class); + } + return null; + } + + @Override + public void stopProxy(String serverId, int id) { + RedisRpcRequest request = buildRequest("streamProxy/stop", id); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); + if (response != null && response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + log.info("[rpc 拉流代理] 停止成功: id: {}", id); + }else { + log.info("[rpc 拉流代理] 停止失败 id: {}", id); + } + } + + @Override + public DownloadFileInfo getRecordPlayUrl(String serverId, Integer recordId) { + RedisRpcRequest request = buildRequest("cloudRecord/play", recordId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); + if (response != null && response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + return JSON.parseObject(response.getBody().toString(), DownloadFileInfo.class); + } + return null; + } + + @Override + public AudioBroadcastResult audioBroadcast(String serverId, String deviceId, String channelDeviceId, Boolean broadcastMode) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("deviceId", deviceId); + jsonObject.put("channelDeviceId", channelDeviceId); + jsonObject.put("broadcastMode", broadcastMode); + RedisRpcRequest request = buildRequest("devicePlay/audioBroadcast", jsonObject.toString()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, userSetting.getPlayTimeout(), TimeUnit.SECONDS); + if (response != null && response.getStatusCode() == ErrorCode.SUCCESS.getCode()) { + return JSON.parseObject(response.getBody().toString(), AudioBroadcastResult.class); + } + return null; + } +} + diff --git a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java index 861821353..b2d65963c 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/redisMsg/service/RedisRpcServiceImpl.java @@ -1,13 +1,16 @@ package com.genersoft.iot.vmp.service.redisMsg.service; import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.CommonCallback; import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.redis.RedisRpcConfig; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcRequest; import com.genersoft.iot.vmp.conf.redis.bean.RedisRpcResponse; -import com.genersoft.iot.vmp.gb28181.bean.SendRtpInfo; +import com.genersoft.iot.vmp.gb28181.bean.*; +import com.genersoft.iot.vmp.gb28181.event.subscribe.catalog.CatalogEvent; import com.genersoft.iot.vmp.gb28181.session.SSRCFactory; import com.genersoft.iot.vmp.media.event.hook.Hook; import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; @@ -22,6 +25,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import java.util.concurrent.TimeUnit; + @Slf4j @Service public class RedisRpcServiceImpl implements IRedisRpcService { @@ -58,8 +63,8 @@ public class RedisRpcServiceImpl implements IRedisRpcService { @Override public SendRtpInfo getSendRtpItem(String callId) { - RedisRpcRequest request = buildRequest("getSendRtpItem", callId); - RedisRpcResponse response = redisRpcConfig.request(request, 10); + RedisRpcRequest request = buildRequest("sendRtp/getSendRtpItem", callId); + RedisRpcResponse response = redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); if (response.getBody() == null) { return null; } @@ -69,9 +74,9 @@ public class RedisRpcServiceImpl implements IRedisRpcService { @Override public WVPResult startSendRtp(String callId, SendRtpInfo sendRtpItem) { log.info("[请求其他WVP] 开始推流,wvp:{}, {}/{}", sendRtpItem.getServerId(), sendRtpItem.getApp(), sendRtpItem.getStream()); - RedisRpcRequest request = buildRequest("startSendRtp", callId); + RedisRpcRequest request = buildRequest("sendRtp/startSendRtp", callId); request.setToId(sendRtpItem.getServerId()); - RedisRpcResponse response = redisRpcConfig.request(request, 10); + RedisRpcResponse response = redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); return JSON.parseObject(response.getBody().toString(), WVPResult.class); } @@ -83,9 +88,9 @@ public class RedisRpcServiceImpl implements IRedisRpcService { return WVPResult.fail(ErrorCode.ERROR100.getCode(), "未找到发流信息"); } log.info("[请求其他WVP] 停止推流,wvp:{}, {}/{}", sendRtpItem.getServerId(), sendRtpItem.getApp(), sendRtpItem.getStream()); - RedisRpcRequest request = buildRequest("stopSendRtp", callId); + RedisRpcRequest request = buildRequest("sendRtp/stopSendRtp", callId); request.setToId(sendRtpItem.getServerId()); - RedisRpcResponse response = redisRpcConfig.request(request, 10); + RedisRpcResponse response = redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); return JSON.parseObject(response.getBody().toString(), WVPResult.class); } @@ -94,7 +99,7 @@ public class RedisRpcServiceImpl implements IRedisRpcService { log.info("[请求所有WVP监听流上线] {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream()); // 监听流上线。 流上线直接发送sendRtpItem消息给实际的信令处理者 Hook hook = Hook.getInstance(HookType.on_media_arrival, sendRtpItem.getApp(), sendRtpItem.getStream(), null); - RedisRpcRequest request = buildRequest("waitePushStreamOnline", sendRtpItem); + RedisRpcRequest request = buildRequest("streamPush/waitePushStreamOnline", sendRtpItem); request.setToId(sendRtpItem.getServerId()); hookSubscribe.addSubscribe(hook, (hookData) -> { @@ -135,9 +140,9 @@ public class RedisRpcServiceImpl implements IRedisRpcService { log.info("[停止WVP监听流上线] {}/{}", sendRtpItem.getApp(), sendRtpItem.getStream()); Hook hook = Hook.getInstance(HookType.on_media_arrival, sendRtpItem.getApp(), sendRtpItem.getStream(), null); hookSubscribe.removeSubscribe(hook); - RedisRpcRequest request = buildRequest("stopWaitePushStreamOnline", sendRtpItem); + RedisRpcRequest request = buildRequest("streamPush/stopWaitePushStreamOnline", sendRtpItem); request.setToId(sendRtpItem.getServerId()); - redisRpcConfig.request(request, 10); + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); } @Override @@ -147,9 +152,9 @@ public class RedisRpcServiceImpl implements IRedisRpcService { log.info("[停止WVP监听流上线] 未找到redis中的发流信息, key:{}", callId); return; } - RedisRpcRequest request = buildRequest("rtpSendStopped", callId); + RedisRpcRequest request = buildRequest("streamPush/rtpSendStopped", callId); request.setToId(sendRtpItem.getServerId()); - redisRpcConfig.request(request, 10); + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); } @Override @@ -166,7 +171,7 @@ public class RedisRpcServiceImpl implements IRedisRpcService { StreamInfo streamInfoParam = new StreamInfo(); streamInfoParam.setApp(app); streamInfoParam.setStream(stream); - RedisRpcRequest request = buildRequest("onStreamOnlineEvent", streamInfoParam); + RedisRpcRequest request = buildRequest("streamPush/onStreamOnlineEvent", streamInfoParam); hookSubscribe.addSubscribe(hook, (hookData) -> { log.info("[请求所有WVP监听流上线] 监听流上线 {}/{}", app, stream); if (callback != null) { @@ -198,7 +203,231 @@ public class RedisRpcServiceImpl implements IRedisRpcService { StreamInfo streamInfoParam = new StreamInfo(); streamInfoParam.setApp(app); streamInfoParam.setStream(stream); - RedisRpcRequest request = buildRequest("unPushStreamOnlineEvent", streamInfoParam); - redisRpcConfig.request(request, 10); + RedisRpcRequest request = buildRequest("streamPush/unPushStreamOnlineEvent", streamInfoParam); + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); + } + + @Override + public void subscribeCatalog(int id, int cycle) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("id", id); + jsonObject.put("cycle", cycle); + RedisRpcRequest request = buildRequest("device/subscribeCatalog", jsonObject); + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); + } + + @Override + public void subscribeMobilePosition(int id, int cycle, int interval) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("id", id); + jsonObject.put("cycle", cycle); + jsonObject.put("interval", cycle); + RedisRpcRequest request = buildRequest("device/subscribeMobilePosition", jsonObject); + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); + } + + @Override + public boolean updatePlatform(String serverId, Platform platform) { + RedisRpcRequest request = buildRequest("platform/update", platform); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 40, TimeUnit.MILLISECONDS); + return Boolean.parseBoolean(response.getBody().toString()); + } + + @Override + public void catalogEventPublish(String serverId, CatalogEvent event) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("platform", event.getPlatform()); + jsonObject.put("channels", event.getChannels()); + jsonObject.put("type", event.getType()); + RedisRpcRequest request = buildRequest("platform/catalogEventPublish", jsonObject); + if (serverId != null) { + request.setToId(serverId); + } + redisRpcConfig.request(request, 10, TimeUnit.MILLISECONDS); + } + + @Override + public WVPResult devicesSync(String serverId, String deviceId) { + RedisRpcRequest request = buildRequest("device/devicesSync", deviceId); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 100, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public SyncStatus getChannelSyncStatus(String serverId, String deviceId) { + RedisRpcRequest request = buildRequest("device/getChannelSyncStatus", deviceId); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 100, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), SyncStatus.class); + } + + @Override + public WVPResult deviceBasicConfig(String serverId, Device device, BasicParam basicParam) { + RedisRpcRequest request = buildRequest("device/deviceBasicConfig", JSONObject.toJSONString(basicParam)); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult deviceConfigQuery(String serverId, Device device, String channelId, String configType) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("configType", configType); + RedisRpcRequest request = buildRequest("device/deviceConfigQuery", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public void teleboot(String serverId, Device device) { + RedisRpcRequest request = buildRequest("device/teleboot", device.getDeviceId()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + if (response.getStatusCode() != ErrorCode.SUCCESS.getCode()) { + throw new ControllerException(response.getStatusCode(), response.getBody().toString()); + } + } + + @Override + public WVPResult recordControl(String serverId, Device device, String channelId, String recordCmdStr) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("recordCmdStr", recordCmdStr); + RedisRpcRequest request = buildRequest("device/record", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult guard(String serverId, Device device, String guardCmdStr) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("guardCmdStr", guardCmdStr); + RedisRpcRequest request = buildRequest("device/guard", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult resetAlarm(String serverId, Device device, String channelId, String alarmMethod, String alarmType) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("alarmMethod", alarmMethod); + jsonObject.put("alarmType", alarmType); + RedisRpcRequest request = buildRequest("device/resetAlarm", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public void iFrame(String serverId, Device device, String channelId) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + RedisRpcRequest request = buildRequest("device/iFrame", jsonObject); + request.setToId(serverId); + redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + } + + @Override + public WVPResult homePosition(String serverId, Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("enabled", enabled); + jsonObject.put("resetTime", resetTime); + jsonObject.put("presetIndex", presetIndex); + RedisRpcRequest request = buildRequest("device/homePosition", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public void dragZoomIn(String serverId, Device device, String channelId, int length, int width, int midpointx, + int midpointy, int lengthx, int lengthy) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("length", length); + jsonObject.put("width", width); + jsonObject.put("midpointx", midpointx); + jsonObject.put("midpointy", midpointy); + jsonObject.put("lengthx", lengthx); + jsonObject.put("lengthy", lengthy); + RedisRpcRequest request = buildRequest("device/dragZoomIn", jsonObject); + request.setToId(serverId); + redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + } + + @Override + public void dragZoomOut(String serverId, Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + jsonObject.put("length", length); + jsonObject.put("width", width); + jsonObject.put("midpointx", midpointx); + jsonObject.put("midpointy", midpointy); + jsonObject.put("lengthx", lengthx); + jsonObject.put("lengthy", lengthy); + RedisRpcRequest request = buildRequest("device/dragZoomOut", jsonObject); + request.setToId(serverId); + redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + } + + @Override + public WVPResult deviceStatus(String serverId, Device device) { + RedisRpcRequest request = buildRequest("device/deviceStatus", device.getDeviceId()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult deviceInfo(String serverId, Device device) { + RedisRpcRequest request = buildRequest("device/info", device.getDeviceId()); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult queryPreset(String serverId, Device device, String channelId) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); + jsonObject.put("channelId", channelId); + RedisRpcRequest request = buildRequest("device/queryPreset", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 60000, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); + } + + @Override + public WVPResult alarm(String serverId, Device device, String startPriority, String endPriority, + String alarmMethod, String alarmType, String startTime, String endTime) { + JSONObject jsonObject = new JSONObject(); + jsonObject.put("device", device.getDeviceId()); +// jsonObject.put("channelId", channelId); + jsonObject.put("startPriority", startPriority); + jsonObject.put("endPriority", endPriority); + jsonObject.put("alarmMethod", alarmMethod); + jsonObject.put("alarmType", alarmType); + jsonObject.put("startTime", startTime); + jsonObject.put("endTime", endTime); + RedisRpcRequest request = buildRequest("device/alarm", jsonObject); + request.setToId(serverId); + RedisRpcResponse response = redisRpcConfig.request(request, 50, TimeUnit.MILLISECONDS); + return JSON.parseObject(response.getBody().toString(), WVPResult.class); } } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java index 238134a9b..1f05a7b48 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/IRedisCatchStorage.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.storager; import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.ServerInfo; import com.genersoft.iot.vmp.common.SystemAllInfo; import com.genersoft.iot.vmp.gb28181.bean.*; import com.genersoft.iot.vmp.media.bean.MediaInfo; @@ -37,7 +38,7 @@ public interface IRedisCatchStorage { /** * 在redis添加wvp的信息 */ - void updateWVPInfo(JSONObject jsonObject, int time); + void updateWVPInfo(ServerInfo serverInfo, int time); /** * 发送推流生成与推流消失消息 @@ -187,4 +188,10 @@ public interface IRedisCatchStorage { void sendStartSendRtp(SendRtpInfo sendRtpItem); void sendPushStreamOnline(SendRtpInfo sendRtpItem); + + ServerInfo queryServerInfo(String serverId); + + String chooseOneServer(String serverId); + + } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java index 7e7ee54c3..f41c2e10c 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/CloudRecordServiceMapper.java @@ -21,6 +21,7 @@ public interface CloudRecordServiceMapper { " folder," + " file_path," + " file_size," + + " server_id," + " time_len ) " + "VALUES (" + " #{app}," + @@ -33,6 +34,7 @@ public interface CloudRecordServiceMapper { " #{folder}," + " #{filePath}," + " #{fileSize}," + + " #{serverId}," + " #{timeLen})" + " ") int add(CloudRecordItem cloudRecordItem); @@ -40,7 +42,7 @@ public interface CloudRecordServiceMapper { @Select(" "}) @@ -138,32 +141,27 @@ public interface MediaServerMapper { ", type=#{type}" + ", transcode_suffix=#{transcodeSuffix}" + ", hook_alive_interval=#{hookAliveInterval}" + + ", server_id=#{serverId}" + "WHERE ip=#{ip} and http_port=#{httpPort}"+ " "}) int updateByHostAndPort(MediaServer mediaServerItem); - @Select("SELECT * FROM wvp_media_server WHERE id=#{id}") - MediaServer queryOne(String id); + @Select("SELECT * FROM wvp_media_server WHERE id=#{id} and server_id = #{serverId}") + MediaServer queryOne(@Param("id") String id, @Param("serverId") String serverId); - @Select("SELECT * FROM wvp_media_server") - List queryAll(); + @Select("SELECT * FROM wvp_media_server where server_id = #{serverId}") + List queryAll(@Param("serverId") String serverId); - @Delete("DELETE FROM wvp_media_server WHERE id=#{id}") - void delOne(String id); + @Delete("DELETE FROM wvp_media_server WHERE id=#{id} and server_id = #{serverId}") + void delOne(String id, @Param("serverId") String serverId); - @Select("DELETE FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}") - void delOneByIPAndPort(@Param("host") String host, @Param("port") int port); + @Select("SELECT * FROM wvp_media_server WHERE ip=#{host} and http_port=#{port} and server_id = #{serverId}") + MediaServer queryOneByHostAndPort(@Param("host") String host, @Param("port") int port, @Param("serverId") String serverId); - @Delete("DELETE FROM wvp_media_server WHERE default_server=true") - int delDefault(); + @Select("SELECT * FROM wvp_media_server WHERE default_server=true and server_id = #{serverId}") + MediaServer queryDefault(@Param("serverId") String serverId); - @Select("SELECT * FROM wvp_media_server WHERE ip=#{host} and http_port=#{port}") - MediaServer queryOneByHostAndPort(@Param("host") String host, @Param("port") int port); - - @Select("SELECT * FROM wvp_media_server WHERE default_server=true") - MediaServer queryDefault(); - - @Select("SELECT * FROM wvp_media_server WHERE record_assist_port > 0") - List queryAllWithAssistPort(); + @Select("SELECT * FROM wvp_media_server WHERE record_assist_port > 0 and server_id = #{serverId}") + List queryAllWithAssistPort(@Param("serverId") String serverId); } diff --git a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java index be73a17cb..4521b0b79 100755 --- a/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/impl/RedisCatchStorageImpl.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.storager.impl; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; +import com.genersoft.iot.vmp.common.ServerInfo; import com.genersoft.iot.vmp.common.SystemAllInfo; import com.genersoft.iot.vmp.common.VideoManagerConstants; import com.genersoft.iot.vmp.conf.UserSetting; @@ -109,10 +110,14 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { @Override - public void updateWVPInfo(JSONObject jsonObject, int time) { + public void updateWVPInfo(ServerInfo serverInfo, int time) { String key = VideoManagerConstants.WVP_SERVER_PREFIX + userSetting.getServerId(); Duration duration = Duration.ofSeconds(time); - redisTemplate.opsForValue().set(key, jsonObject, duration); + redisTemplate.opsForValue().set(key, serverInfo, duration); + // 设置平台的分数值 + String setKey = VideoManagerConstants.WVP_SERVER_LIST; + // 首次设置就设置为0, 后续值越小说明越是最近启动的 + redisTemplate.opsForZSet().add(setKey, userSetting.getServerId(), System.currentTimeMillis()); } @Override @@ -532,4 +537,21 @@ public class RedisCatchStorageImpl implements IRedisCatchStorage { log.info("[redis发送通知] 流上线 {}: {}/{}->{}", key, sendRtpItem.getApp(), sendRtpItem.getStream(), sendRtpItem.getTargetId()); redisTemplate.convertAndSend(key, JSON.toJSON(sendRtpItem)); } + + @Override + public ServerInfo queryServerInfo(String serverId) { + String key = VideoManagerConstants.WVP_SERVER_PREFIX + serverId; + return (ServerInfo)redisTemplate.opsForValue().get(key); + } + + @Override + public String chooseOneServer(String serverId) { + String key = VideoManagerConstants.WVP_SERVER_LIST; + redisTemplate.opsForZSet().remove(key, serverId); + Set range = redisTemplate.opsForZSet().range(key, 0, 0); + if (range == null || range.isEmpty()) { + return null; + } + return (String) range.iterator().next(); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxy.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxy.java index cdb2470f6..61f6e6553 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxy.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxy.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.streamProxy.bean; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -29,9 +30,15 @@ public class StreamProxy extends CommonGBChannel { @Schema(description = "流ID") private String stream; - @Schema(description = "流媒体服务ID") + @Schema(description = "当前拉流使用的流媒体服务ID") private String mediaServerId; + @Schema(description = "固定选择的流媒体服务ID") + private String relatesMediaServerId; + + @Schema(description = "服务ID") + private String serverId; + @Schema(description = "拉流地址") private String srcUrl; @@ -72,7 +79,8 @@ public class StreamProxy extends CommonGBChannel { if (ObjectUtils.isEmpty(this.getGbName())) { this.setGbName( app+ "-" +stream); } - this.setStreamProxyId(this.getId()); + this.setDataType(ChannelDataType.STREAM_PROXY.value); + this.setDataDeviceId(this.getId()); return this; } } diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxyParam.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxyParam.java index 632ca998a..d791c3195 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxyParam.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/bean/StreamProxyParam.java @@ -53,11 +53,12 @@ public class StreamProxyParam { private boolean enableDisableNoneReader; - public StreamProxy buildStreamProxy() { + public StreamProxy buildStreamProxy(String serverId) { StreamProxy streamProxy = new StreamProxy(); streamProxy.setApp(app); streamProxy.setStream(stream); - streamProxy.setMediaServerId(mediaServerId); + streamProxy.setRelatesMediaServerId(mediaServerId); + streamProxy.setServerId(serverId); streamProxy.setSrcUrl(url); streamProxy.setTimeout(timeoutMs/1000); streamProxy.setRtspType(rtpType); diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/controller/StreamProxyController.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/controller/StreamProxyController.java index 543043851..be4d91b33 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/controller/StreamProxyController.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/controller/StreamProxyController.java @@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.streamProxy.controller; import com.alibaba.fastjson2.JSONObject; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.conf.security.JwtUtils; import com.genersoft.iot.vmp.media.bean.MediaServer; @@ -19,7 +20,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Controller; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; @@ -44,6 +44,9 @@ public class StreamProxyController { @Autowired private IStreamProxyPlayService streamProxyPlayService; + @Autowired + private UserSetting userSetting; + @Operation(summary = "分页查询流代理", security = @SecurityRequirement(name = JwtUtils.HEADER)) @Parameter(name = "page", description = "当前页") @@ -112,8 +115,8 @@ public class StreamProxyController { @ResponseBody public StreamProxy add(@RequestBody StreamProxy param){ log.info("添加代理: " + JSONObject.toJSONString(param)); - if (ObjectUtils.isEmpty(param.getMediaServerId())) { - param.setMediaServerId(null); + if (ObjectUtils.isEmpty(param.getRelatesMediaServerId())) { + param.setRelatesMediaServerId(null); } if (ObjectUtils.isEmpty(param.getType())) { param.setType("default"); @@ -121,6 +124,7 @@ public class StreamProxyController { if (ObjectUtils.isEmpty(param.getGbId())) { param.setGbDeviceId(null); } + param.setServerId(userSetting.getServerId()); streamProxyService.add(param); return param; } @@ -135,6 +139,9 @@ public class StreamProxyController { if (param.getId() == 0) { throw new ControllerException(ErrorCode.ERROR400.getCode(), "缺少代理信息的ID"); } + if (ObjectUtils.isEmpty(param.getRelatesMediaServerId())) { + param.setRelatesMediaServerId(null); + } if (ObjectUtils.isEmpty(param.getGbId())) { param.setGbDeviceId(null); } @@ -185,7 +192,7 @@ public class StreamProxyController { @Parameter(name = "id", description = "代理Id", required = true) public StreamContent start(int id){ log.info("播放代理: {}", id); - StreamInfo streamInfo = streamProxyPlayService.start(id); + StreamInfo streamInfo = streamProxyPlayService.start(id, null, null); if (streamInfo == null) { throw new ControllerException(ErrorCode.ERROR100.getCode(), ErrorCode.ERROR100.getMsg()); }else { diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/StreamProxyMapper.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/StreamProxyMapper.java index 82d48e212..4258458b7 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/StreamProxyMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/StreamProxyMapper.java @@ -11,12 +11,12 @@ import java.util.List; @Repository public interface StreamProxyMapper { - @Insert("INSERT INTO wvp_stream_proxy (type, app, stream,media_server_id, src_url, " + - "timeout, ffmpeg_cmd_key, rtsp_type, enable_audio, enable_mp4, enable, pulling, stream_key, " + - "enable_remove_none_reader, enable_disable_none_reader, create_time) VALUES" + - "(#{type}, #{app}, #{stream}, #{mediaServerId}, #{srcUrl}, " + - "#{timeout}, #{ffmpegCmdKey}, #{rtspType}, #{enableAudio}, #{enableMp4}, #{enable}, #{pulling}, #{streamKey}, " + - "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{createTime} )") + @Insert("INSERT INTO wvp_stream_proxy (type, app, stream,relates_media_server_id, src_url, " + + "timeout, ffmpeg_cmd_key, rtsp_type, enable_audio, enable_mp4, enable, pulling, " + + "enable_remove_none_reader, enable_disable_none_reader, server_id, create_time) VALUES" + + "(#{type}, #{app}, #{stream}, #{relatesMediaServerId}, #{srcUrl}, " + + "#{timeout}, #{ffmpegCmdKey}, #{rtspType}, #{enableAudio}, #{enableMp4}, #{enable}, #{pulling}, " + + "#{enableRemoveNoneReader}, #{enableDisableNoneReader}, #{serverId}, #{createTime} )") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") int add(StreamProxy streamProxyDto); @@ -24,7 +24,7 @@ public interface StreamProxyMapper { "SET type=#{type}, " + "app=#{app}," + "stream=#{stream}," + - "media_server_id=#{mediaServerId}, " + + "relates_media_server_id=#{relatesMediaServerId}, " + "src_url=#{srcUrl}," + "timeout=#{timeout}, " + "ffmpeg_cmd_key=#{ffmpegCmdKey}, " + @@ -32,7 +32,6 @@ public interface StreamProxyMapper { "enable_audio=#{enableAudio}, " + "enable=#{enable}, " + "pulling=#{pulling}, " + - "stream_key=#{streamKey}, " + "enable_remove_none_reader=#{enableRemoveNoneReader}, " + "enable_disable_none_reader=#{enableDisableNoneReader}, " + "enable_mp4=#{enableMp4} " + @@ -84,8 +83,14 @@ public interface StreamProxyMapper { StreamProxy select(@Param("id") int id); @Update("UPDATE wvp_stream_proxy " + - "SET pulling=false, " + - "stream_key = null " + - "WHERE id=#{id}") + " SET pulling=false, media_server_id = null," + + " stream_key = null " + + " WHERE id=#{id}") void removeStream(@Param("id")int id); + + @Update("UPDATE wvp_stream_proxy " + + " SET pulling=#{pulling}, media_server_id = #{mediaServerId}, " + + " stream_key = #{streamKey} " + + " WHERE id=#{id}") + void addStream(StreamProxy streamProxy); } diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/provider/StreamProxyProvider.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/provider/StreamProxyProvider.java index 6586fc647..968a74b70 100644 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/provider/StreamProxyProvider.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/dao/provider/StreamProxyProvider.java @@ -1,5 +1,7 @@ package com.genersoft.iot.vmp.streamProxy.dao.provider; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; + import java.util.Map; public class StreamProxyProvider { @@ -7,12 +9,13 @@ public class StreamProxyProvider { public String getBaseSelectSql(){ return "SELECT " + " st.*, " + - " st.id as stream_proxy_id, " + + ChannelDataType.STREAM_PROXY.value + " as data_type, " + + " st.id as data_device_id, " + " wdc.*, " + " wdc.id as gb_id" + " FROM wvp_stream_proxy st " + " LEFT join wvp_device_channel wdc " + - " on st.id = wdc.stream_proxy_id "; + " on wdc.data_type = 3 and st.id = wdc.data_device_id "; } public String select(Map params ){ @@ -20,7 +23,7 @@ public class StreamProxyProvider { } public String selectForPushingInMediaServer(Map params ){ - return getBaseSelectSql() + " WHERE st.pulling=1 and st.media_server_id=#{mediaServerId} order by st.create_time desc"; + return getBaseSelectSql() + " WHERE st.pulling=true and st.media_server_id=#{mediaServerId} order by st.create_time desc"; } public String selectOneByAppAndStream(Map params ){ diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/IStreamProxyPlayService.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/IStreamProxyPlayService.java index 9f9ebf6f8..284c90bf2 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/IStreamProxyPlayService.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/IStreamProxyPlayService.java @@ -1,11 +1,14 @@ package com.genersoft.iot.vmp.streamProxy.service; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; public interface IStreamProxyPlayService { - StreamInfo start(int id); + StreamInfo start(int id, Boolean record, ErrorCallback callback); + + void start(int id, ErrorCallback callback); StreamInfo startProxy(StreamProxy streamProxy); diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyPlayServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyPlayServiceImpl.java index 170ed6fdc..a6cffa93f 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyPlayServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyPlayServiceImpl.java @@ -1,26 +1,42 @@ package com.genersoft.iot.vmp.streamProxy.service.impl; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.conf.UserSetting; +import com.genersoft.iot.vmp.conf.DynamicTask; +import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; +import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.bean.MediaServer; +import com.genersoft.iot.vmp.media.event.hook.Hook; +import com.genersoft.iot.vmp.media.event.hook.HookSubscribe; +import com.genersoft.iot.vmp.media.event.hook.HookType; +import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.media.service.IMediaServerService; +import com.genersoft.iot.vmp.service.redisMsg.IRedisRpcPlayService; +import com.genersoft.iot.vmp.service.bean.ErrorCallback; +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; import com.genersoft.iot.vmp.streamProxy.dao.StreamProxyMapper; import com.genersoft.iot.vmp.streamProxy.service.IStreamProxyPlayService; import com.genersoft.iot.vmp.vmanager.bean.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import javax.sip.message.Response; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + /** * 视频代理业务 */ @Slf4j @Service -@DS("master") public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService { @Autowired @@ -29,13 +45,96 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService { @Autowired private IMediaServerService mediaServerService; + @Autowired + private HookSubscribe subscribe; + + @Autowired + private DynamicTask dynamicTask; + + @Autowired + private UserSetting userSetting; + + @Autowired + private IRedisRpcPlayService redisRpcPlayService; + + private ConcurrentHashMap> callbackMap = new ConcurrentHashMap<>(); + + private ConcurrentHashMap streamInfoMap = new ConcurrentHashMap<>(); + + /** + * 流到来的处理 + */ + @Async("taskExecutor") + @Transactional + @EventListener + public void onApplicationEvent(MediaArrivalEvent event) { + if ("rtsp".equals(event.getSchema())) { + StreamProxy streamProxy = streamProxyMapper.selectOneByAppAndStream(event.getApp(), event.getStream()); + if (streamProxy != null) { + ErrorCallback callback = callbackMap.remove(streamProxy.getId()); + StreamInfo streamInfo = streamInfoMap.remove(streamProxy.getId()); + if (callback != null && streamInfo != null) { + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + } + } + } + } + @Override - public StreamInfo start(int id) { + public void start(int id, ErrorCallback callback) { StreamProxy streamProxy = streamProxyMapper.select(id); if (streamProxy == null) { throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到"); } - return startProxy(streamProxy); + StreamInfo streamInfo = startProxy(streamProxy); + if (streamInfo == null) { + callback.run(Response.BUSY_HERE, "busy here", null); + return; + } + callbackMap.put(id, callback); + streamInfoMap.put(id, streamInfo); + + MediaServer mediaServer = mediaServerService.getOne(streamProxy.getMediaServerId()); + if (mediaServer != null) { + MediaInfo mediaInfo = mediaServerService.getMediaInfo(mediaServer, streamProxy.getApp(), streamProxy.getStream()); + if (mediaInfo != null) { + callbackMap.remove(id); + streamInfoMap.remove(id); + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + } + } + } + + @Override + public StreamInfo start(int id, Boolean record, ErrorCallback callback) { + StreamProxy streamProxy = streamProxyMapper.select(id); + if (streamProxy == null) { + throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到"); + } + if (record != null) { + streamProxy.setEnableMp4(record); + } + + StreamInfo streamInfo = startProxy(streamProxy); + if (callback != null) { + // 设置流超时的定时任务 + String timeOutTaskKey = UUID.randomUUID().toString(); + Hook rtpHook = Hook.getInstance(HookType.on_media_arrival, streamProxy.getApp(), streamProxy.getStream(), streamInfo.getMediaServer().getId()); + dynamicTask.startDelay(timeOutTaskKey, () -> { + // 收流超时 + subscribe.removeSubscribe(rtpHook); + callback.run(InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getCode(), InviteErrorCode.ERROR_FOR_STREAM_TIMEOUT.getMsg(), streamInfo); + }, userSetting.getPlayTimeout()); + + // 开启流到来的监听 + subscribe.addSubscribe(rtpHook, (hookData) -> { + dynamicTask.stop(timeOutTaskKey); + // hook响应 + callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo); + subscribe.removeSubscribe(rtpHook); + }); + } + return streamInfo; } @Override @@ -43,23 +142,27 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService { if (!streamProxy.isEnable()) { return null; } + if (streamProxy.getServerId() == null) { + streamProxy.setServerId(userSetting.getServerId()); + } + if (!userSetting.getServerId().equals(streamProxy.getServerId())) { + return redisRpcPlayService.playProxy(streamProxy.getServerId(), streamProxy.getId()); + } + MediaServer mediaServer; - String mediaServerId = streamProxy.getMediaServerId(); + String mediaServerId = streamProxy.getRelatesMediaServerId(); if (mediaServerId == null) { mediaServer = mediaServerService.getMediaServerForMinimumLoad(null); }else { mediaServer = mediaServerService.getOne(mediaServerId); - if (mediaServer == null) { - mediaServer = mediaServerService.getMediaServerForMinimumLoad(null); - } } if (mediaServer == null) { - throw new ControllerException(ErrorCode.ERROR100.getCode(), "未找到可用的媒体节点"); + throw new ControllerException(ErrorCode.ERROR100.getCode(), mediaServerId == null?"未找到可用的媒体节点":"未找到节点" + mediaServerId); } StreamInfo streamInfo = mediaServerService.startProxy(mediaServer, streamProxy); if (mediaServerId == null || !mediaServerId.equals(mediaServer.getId())) { streamProxy.setMediaServerId(mediaServer.getId()); - streamProxyMapper.update(streamProxy); + streamProxyMapper.addStream(streamProxy); } return streamInfo; } @@ -70,6 +173,10 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService { if (streamProxy == null) { throw new ControllerException(ErrorCode.ERROR404.getCode(), "代理信息未找到"); } + if (!userSetting.getServerId().equals(streamProxy.getServerId())) { + redisRpcPlayService.stopProxy(streamProxy.getServerId(), streamProxy.getId()); + return; + } stopProxy(streamProxy); } @@ -88,9 +195,6 @@ public class StreamProxyPlayServiceImpl implements IStreamProxyPlayService { }else { mediaServerService.stopProxy(mediaServer, streamProxy.getStreamKey()); } - streamProxy.setMediaServerId(mediaServer.getId()); - streamProxy.setStreamKey(null); - streamProxy.setPulling(false); streamProxyMapper.removeStream(streamProxy.getId()); } diff --git a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyServiceImpl.java index cf1818d9a..6c89b02d8 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/streamProxy/service/impl/StreamProxyServiceImpl.java @@ -1,8 +1,8 @@ package com.genersoft.iot.vmp.streamProxy.service.impl; import com.alibaba.fastjson2.JSONObject; -import com.baomidou.dynamic.datasource.annotation.DS; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.conf.UserSetting; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; @@ -47,7 +47,6 @@ import java.util.Map; */ @Slf4j @Service -@DS("master") public class StreamProxyServiceImpl implements IStreamProxyService { @Autowired @@ -146,7 +145,7 @@ public class StreamProxyServiceImpl implements IStreamProxyService { if (param.getMediaServerId().equals("auto")) { param.setMediaServerId(null); } - StreamProxy streamProxy = param.buildStreamProxy(); + StreamProxy streamProxy = param.buildStreamProxy(userSetting.getServerId()); if (streamProxyInDb == null) { add(streamProxy); @@ -179,7 +178,8 @@ public class StreamProxyServiceImpl implements IStreamProxyService { streamProxy.setCreateTime(DateUtil.getNow()); streamProxy.setUpdateTime(DateUtil.getNow()); streamProxyMapper.add(streamProxy); - streamProxy.setStreamProxyId(streamProxy.getId()); + streamProxy.setDataType(ChannelDataType.STREAM_PROXY.value); + streamProxy.setDataDeviceId(streamProxy.getId()); } @Override @@ -404,11 +404,10 @@ public class StreamProxyServiceImpl implements IStreamProxyService { return; } streamProxy.setPulling(status); - if (!mediaServerId.equals(streamProxy.getMediaServerId())) { - streamProxy.setMediaServerId(mediaServerId); - } + streamProxy.setMediaServerId(mediaServerId); streamProxy.setUpdateTime(DateUtil.getNow()); - streamProxyMapper.update(streamProxy); + streamProxyMapper.addStream(streamProxy); + streamProxy.setGbStatus(status ? "ON" : "OFF"); if (streamProxy.getGbId() > 0) { if (status) { diff --git a/src/main/java/com/genersoft/iot/vmp/streamPush/bean/StreamPush.java b/src/main/java/com/genersoft/iot/vmp/streamPush/bean/StreamPush.java index 876188aa6..ef4517bdd 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamPush/bean/StreamPush.java +++ b/src/main/java/com/genersoft/iot/vmp/streamPush/bean/StreamPush.java @@ -1,6 +1,7 @@ package com.genersoft.iot.vmp.streamPush.bean; import com.genersoft.iot.vmp.common.StreamInfo; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; import com.genersoft.iot.vmp.utils.DateUtil; @@ -78,6 +79,8 @@ public class StreamPush extends CommonGBChannel implements Comparable> batchStop(Integer id){ + public DeferredResult> start(Integer id){ Assert.notNull(id, "推流ID不可为NULL"); DeferredResult> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue()); result.onTimeout(()->{ @@ -259,4 +260,12 @@ public class StreamPushController { }, null, null); return result; } + + @GetMapping(value = "/forceClose") + @ResponseBody + @Operation(summary = "强制停止推流", security = @SecurityRequirement(name = JwtUtils.HEADER)) + public void stop(String app, String stream){ + + streamPushPlayService.stop(app, stream); + } } diff --git a/src/main/java/com/genersoft/iot/vmp/streamPush/dao/StreamPushMapper.java b/src/main/java/com/genersoft/iot/vmp/streamPush/dao/StreamPushMapper.java index 64b81d587..c77fa4194 100755 --- a/src/main/java/com/genersoft/iot/vmp/streamPush/dao/StreamPushMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/streamPush/dao/StreamPushMapper.java @@ -1,5 +1,6 @@ package com.genersoft.iot.vmp.streamPush.dao; +import com.genersoft.iot.vmp.common.enums.ChannelDataType; import com.genersoft.iot.vmp.streamPush.bean.StreamPush; import com.genersoft.iot.vmp.service.bean.StreamPushItemFromRedis; import org.apache.ibatis.annotations.*; @@ -13,6 +14,8 @@ import java.util.Set; @Repository public interface StreamPushMapper { + Integer dataType = ChannelDataType.GB28181.value; + @Insert("INSERT INTO wvp_stream_push (app, stream, media_server_id, server_id, push_time, update_time, create_time, pushing, start_offline_push) VALUES" + "(#{app}, #{stream}, #{mediaServerId} , #{serverId} , #{pushTime} ,#{updateTime}, #{createTime}, #{pushing}, #{startOfflinePush})") @Options(useGeneratedKeys = true, keyProperty = "id", keyColumn = "id") @@ -39,13 +42,13 @@ public interface StreamPushMapper { @Select(value = {" "}) List selectAll(@Param("query") String query, @Param("pushing") Boolean pushing, @Param("mediaServerId") String mediaServerId); - @Select("SELECT st.*, st.id as stream_push_id, wdc.*, wdc.id as gb_id FROM wvp_stream_push st LEFT join wvp_device_channel wdc on st.id = wdc.stream_push_id WHERE st.app=#{app} AND st.stream=#{stream}") + @Select("SELECT st.*, st.id as data_device_id, wdc.*, wdc.id as gb_id FROM wvp_stream_push st LEFT join wvp_device_channel wdc on wdc.data_type = 2 and st.id = wdc.data_device_id WHERE st.app=#{app} AND st.stream=#{stream}") StreamPush selectByAppAndStream(@Param("app") String app, @Param("stream") String stream); @Insert(" + +
diff --git a/web_src/src/App.vue b/web_src/src/App.vue index 103cbe1a0..cf778a839 100755 --- a/web_src/src/App.vue +++ b/web_src/src/App.vue @@ -69,7 +69,7 @@ body, background-color: #f0f2f5; color: #333; text-align: center; - padding-top: 0px !important; + padding: 0 20px; } /*定义滚动条高宽及背景 高宽分别对应横竖滚动条的尺寸*/ diff --git a/web_src/src/components/ChannelEdit.vue b/web_src/src/components/ChannelEdit.vue index 80f116e60..569952cf9 100644 --- a/web_src/src/components/ChannelEdit.vue +++ b/web_src/src/components/ChannelEdit.vue @@ -2,9 +2,7 @@
- + - + - + - + - + + - + - - - - - - - - - - + + + + + + + + @@ -116,6 +124,7 @@ import uiHeader from '../layout/UiHeader.vue' import deviceEdit from './dialog/deviceEdit.vue' import syncChannelProgress from './dialog/SyncChannelProgress.vue' import configInfo from "./dialog/configInfo.vue"; +import Vue from "vue"; export default { name: 'app', @@ -133,8 +142,7 @@ export default { online: null, videoComponentList: [], updateLooper: 0, //数据刷新轮训标志 - currentDeviceChannelsLenth: 0, - winHeight: window.innerHeight - 200, + currentDeviceChannelsLength: 0, currentPage: 1, count: 15, total: 0, @@ -142,6 +150,9 @@ export default { }; }, computed: { + Vue() { + return Vue + }, getcurrentDeviceChannels: function () { let data = this.currentDevice['channelMap']; let channels = null; @@ -149,7 +160,7 @@ export default { channels = Object.keys(data).map(key => { return data[key]; }); - this.currentDeviceChannelsLenth = channels.length; + this.currentDeviceChannelsLength = channels.length; } return channels; } @@ -164,6 +175,8 @@ export default { }, methods: { initData: function () { + this.currentPage = 1; + this.total= 0; this.getDeviceList(); }, currentChange: function (val) { @@ -327,15 +340,12 @@ export default { }) }, showInfo: function (){ - this.$axios({ method: 'get', url: `/api/server/system/configInfo`, }).then( (res)=> { - console.log(res) if (res.data.code === 0) { - console.log(2222) - console.log(this.$refs.configInfo) + this.serverId = res.data.data.addOn.serverId; this.$refs.configInfo.openDialog(res.data.data) } }).catch( (error)=> { @@ -346,6 +356,10 @@ export default { this.setGuard(itemData) }else if (command === "resetGuard") { this.resetGuard(itemData) + }else if (command === "delete") { + this.deleteDevice(itemData) + }else if (command === "syncBasicParam") { + this.syncBasicParam(itemData) } }, setGuard: function (itemData) { @@ -394,6 +408,94 @@ export default { }) }); }, + subscribeForCatalog: function (data, value) { + console.log(data) + console.log(value) + this.$axios({ + method: 'get', + url: `/api/device/query/subscribe/catalog`, + params: { + id: data, + cycle: value?60:0 + } + }).then( (res)=> { + if (res.data.code === 0) { + this.$message.success({ + showClose: true, + message: value?"订阅成功":"取消订阅成功" + }) + }else { + this.$message.error({ + showClose: true, + message: res.data.msg + }) + } + }).catch( (error)=> { + this.$message.error({ + showClose: true, + message: error.message + }) + }); + + }, + subscribeForMobilePosition: function (data, value) { + console.log(data) + console.log(value) + this.$axios({ + method: 'get', + url: `/api/device/query/subscribe/mobile-position`, + params: { + id: data, + cycle: value?60:0, + interval: value?5:0 + } + }).then( (res)=> { + if (res.data.code === 0) { + this.$message.success({ + showClose: true, + message: value?"订阅成功":"取消订阅成功" + }) + }else { + this.$message.error({ + showClose: true, + message: res.data.msg + }) + } + }).catch( (error)=> { + this.$message.error({ + showClose: true, + message: error.message + }) + }); + }, + syncBasicParam: function (data) { + console.log(data) + this.$axios({ + method: 'get', + url: `/api/device/config/query/${data.deviceId}/BasicParam`, + params: { + // channelId: data.deviceId + } + }).then( (res)=> { + if (res.data.code === 0) { + this.$message.success({ + showClose: true, + message: `配置已同步,当前心跳间隔: ${res.data.data.BasicParam.HeartBeatInterval} 心跳间隔:${res.data.data.BasicParam.HeartBeatCount}` + }) + }else { + this.$message.error({ + showClose: true, + message: res.data.msg + }) + } + }).catch( (error)=> { + this.$message.error({ + showClose: true, + message: error.message + }) + }); + + }, } }; diff --git a/web_src/src/components/GBRecordDetail.vue b/web_src/src/components/GBRecordDetail.vue index 288bfe193..dfb02fcde 100755 --- a/web_src/src/components/GBRecordDetail.vue +++ b/web_src/src/components/GBRecordDetail.vue @@ -64,12 +64,8 @@ 倍速 - - 0.25倍速 - 0.5倍速 - 1倍速 - 2倍速 - 4倍速 + + {{item}}倍速 @@ -115,6 +111,7 @@ return { deviceId: this.$route.params.deviceId, channelId: this.$route.params.channelId, + downloadSpeedArray: [0.25, 0.5, 1, 2, 4], recordsLoading: false, streamId: "", hasAudio: false, @@ -184,6 +181,7 @@ this.playerBoxStyle["height"] = this.winHeight + "px"; this.chooseDate = moment().format('YYYY-MM-DD') this.dateChange(); + this.getDownloadSpeedArray() window.addEventListener('beforeunload', this.stopPlayRecord) }, destroyed() { @@ -274,6 +272,27 @@ }); } }, + getDownloadSpeedArray(){ + this.$axios({ + method: 'get', + url: '/api/device/query/channel/one', + params: { + deviceId: this.deviceId, + channelDeviceId: this.channelId, + } + }).then((res)=> { + if (res.data.code === 0 && res.data.data.downloadSpeed) { + let speedArray = res.data.data.downloadSpeed.split('/'); + + speedArray.forEach(item => { + if (parseInt(item) > 4) { + this.downloadSpeedArray.push(parseInt(item)); + console.log(this.downloadSpeedArray); + } + }) + } + }) + }, gbPlay(){ console.log('前端控制:播放'); this.$axios({ @@ -317,7 +336,7 @@ this.$axios({ method: 'get', url: '/api/gb_record/download/start/' + this.deviceId + '/' + this.channelId + '?startTime=' + row.startTime + '&endTime=' + - row.endTime + '&downloadSpeed=4' + row.endTime + '&downloadSpeed='+ this.downloadSpeedArray[this.downloadSpeedArray.length - 1] }).then( (res)=> { if (res.data.code === 0) { let streamInfo = res.data.data; diff --git a/web_src/src/components/PlatformEdit.vue b/web_src/src/components/PlatformEdit.vue index ec42280a0..246ba8635 100644 --- a/web_src/src/components/PlatformEdit.vue +++ b/web_src/src/components/PlatformEdit.vue @@ -2,9 +2,7 @@
- @@ -67,7 +67,6 @@ export default { return { recordPlanList: [], searchSrt: "", - winHeight: window.innerHeight - 180, currentPage: 1, count: 15, total: 0, diff --git a/web_src/src/components/StreamProxyEdit.vue b/web_src/src/components/StreamProxyEdit.vue index 12413bfc9..eb0410121 100644 --- a/web_src/src/components/StreamProxyEdit.vue +++ b/web_src/src/components/StreamProxyEdit.vue @@ -2,9 +2,7 @@