Merge remote-tracking branch 'origin/master'

This commit is contained in:
tianxin 2025-03-14 21:02:17 +08:00
commit 89009bce07
235 changed files with 15753 additions and 4642 deletions

View File

@ -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),没有使用时间限制,需要源码可以星球私信我或者邮箱联系。

View File

@ -199,13 +199,6 @@
<artifactId>springdoc-openapi-security</artifactId>
<version>1.6.10</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.baomidou/dynamic-datasource-spring-boot-starter -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.6.1</version>
</dependency>
<!--在线文档 -->
<dependency>

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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:";

View File

@ -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;
}
}

View File

@ -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<String> 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;
}

View File

@ -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<Platform> parentPlatforms = platformService.queryEnablePlatformList();
List<Platform> parentPlatforms = platformService.queryEnablePlatformList(userSetting.getServerId());
for (Platform platform : parentPlatforms) {

View File

@ -37,6 +37,11 @@ public class UserSetting {
*/
private Integer playTimeout = 10000;
/**
* 获取设备录像数据超时时间,单位毫秒
*/
private Integer recordInfoTimeout = 15000;
/**
* 上级点播等待超时时间,单位毫秒
*/
@ -170,4 +175,20 @@ public class UserSetting {
*/
private int gbDeviceOnline = 1;
/**
* 登录超时时间(分钟)
*/
private long loginTimeout = 30;
/**
* jwk文件路径若不指定则使用resources目录下的jwk.json
*/
private String jwkFile = "classpath:jwk.json";
/**
* wvp集群模式下如果注册向上级的wvp奔溃则自动选择一个其他wvp继续注册到上级
*/
private boolean autoRegisterPlatform = false;
}

View File

@ -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);
}
}

View File

@ -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<Object, Object> redisTemplate;
@ -48,6 +49,40 @@ public class RedisRpcConfig implements MessageListener {
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
private final static Map<String, RedisRpcClassHandler> protocolHash = new HashMap<>();
public void addHandler(String path, RedisRpcClassHandler handler) {
protocolHash.put(path, handler);
}
// @Override
// public void run(String... args) throws Exception {
// List<Class<?>> 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<Long, SynchronousQueue<RedisRpcResponse>> topicSubscribers = new ConcurrentHashMap<>();
private final Map<Long, CommonCallback<RedisRpcResponse>> 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<RedisRpcResponse> 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<RedisRpcResponse> 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());

View File

@ -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;
}
}

View File

@ -1,5 +1,6 @@
package com.genersoft.iot.vmp.conf.security;
import com.genersoft.iot.vmp.conf.UserSetting;
import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
import com.genersoft.iot.vmp.service.IUserApiKeyService;
import com.genersoft.iot.vmp.service.IUserService;
@ -20,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;
@ -53,6 +58,8 @@ public class JwtUtils implements InitializingBean {
private static IUserService userService;
private static IUserApiKeyService userApiKeyService;
private static UserSetting userSetting;
public static String getApiKeyHeader() {
return API_KEY_HEADER;
@ -68,6 +75,11 @@ public class JwtUtils implements InitializingBean {
JwtUtils.userApiKeyService = userApiKeyService;
}
@Resource
public void setUserSetting(UserSetting userSetting) {
JwtUtils.userSetting = userSetting;
}
@Override
public void afterPropertiesSet() {
try {
@ -84,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<JsonWebKey> jsonWebKeys = jsonWebKeySet.getJsonWebKeys();
if (!jsonWebKeys.isEmpty()) {
@ -94,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;
}
@ -153,7 +204,7 @@ public class JwtUtils implements InitializingBean {
}
public static String createToken(String username) {
return createToken(username, EXPIRATION_TIME);
return createToken(username, userSetting.getLoginTimeout());
}
public static String getHeader() {

View File

@ -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()));

View File

@ -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());
}

View File

@ -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.
*

View File

@ -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;
}
}

View File

@ -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 = "创建时间")
private String createTime;

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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 "";
}
}

View File

@ -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 "";
}
}

View File

@ -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 "";
}
}

View File

@ -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 "";
}
}

View File

@ -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 "";
}
}

View File

@ -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 "";
}
}

View File

@ -0,0 +1,6 @@
package com.genersoft.iot.vmp.gb28181.bean;
public enum FrontEndControlType {
PTZ,FI,PRESET,TOUR,SCAN,AUXILIARY
}

View File

@ -0,0 +1,7 @@
package com.genersoft.iot.vmp.gb28181.bean;
public interface IFrontEndControlCode {
FrontEndControlType getType();
String encode();
}

View File

@ -4,7 +4,7 @@ import lombok.Data;
// 从INVITE消息中解析需要的信息
@Data
public class InviteInfo {
public class InviteMessageInfo {
private String requesterId;
private String targetChannelId;
private String sourceChannelId;

View File

@ -127,4 +127,7 @@ public class Platform {
@Schema(description = "保密属性必选缺省为00-不涉密1-涉密")
private int secrecy = 0;
@Schema(description = "执行注册的服务ID")
private String serverId;
}

View File

@ -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));

View File

@ -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<CommonGBChannel> 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<CommonGBChannel> 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;
}
}

View File

@ -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<String> 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<WVPResult<String>> 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<String> result = new DeferredResult<String>(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<WVPResult<String>> 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<String> 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<WVPResult<Object>> 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<String> result = new DeferredResult<String > (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<WVPResult<Object>> 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;
}
}

View File

@ -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<ResponseEntity<WVPResult<String>>> recordApi(@PathVariable String deviceId,
@PathVariable String recordCmdStr, String channelId) {
@GetMapping("/record")
public DeferredResult<WVPResult<String>> 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<ResponseEntity<WVPResult<String>>> 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<WVPResult<String>> 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<WVPResult<String>> guardApi(@PathVariable String deviceId, @PathVariable String guardCmdStr) {
@GetMapping("/guard")
public DeferredResult<WVPResult<String>> 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<WVPResult<String>> 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<WVPResult<String>> 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<ResponseEntity<WVPResult<String>>> 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<WVPResult<String>> 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<ResponseEntity<WVPResult<String>>> 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<WVPResult<String>> 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<WVPResult<String>> 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<WVPResult<String>> 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<WVPResult<String>> 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("<DragZoomIn>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomIn>\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<WVPResult<String>> 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<WVPResult<String>> 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("<DragZoomOut>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomOut>\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<WVPResult<String>> 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;
}
}

View File

@ -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<SyncStatus> 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<ResponseEntity<String>> deviceStatusApi(@PathVariable String deviceId) {
public DeferredResult<WVPResult<String>> 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<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String>>(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<WVPResult<String>> 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<ResponseEntity<String>> alarmApi(@PathVariable String deviceId,
@GetMapping("/alarm")
public DeferredResult<WVPResult<Object>> 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<ResponseEntity<String>> result = new DeferredResult<ResponseEntity<String >> (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<WVPResult<Object>> 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<WVPResult<Object>> deviceInfo(String deviceId) {
if (log.isDebugEnabled()) {
log.debug("设备信息查询API调用");
}
Device device = deviceService.getDeviceByDeviceId(deviceId);
Assert.notNull(device, "设备不存在");
DeferredResult<WVPResult<Object>> 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);
}
}

View File

@ -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<WVPResult<RecordInfo>> result = new DeferredResult<>();
DeferredResult<WVPResult<RecordInfo>> 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<RecordInfo> 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<RecordInfo> wvpResult = new WVPResult<>();
wvpResult.setCode(code);
wvpResult.setMsg(msg);
wvpResult.setData(data);
result.setResult(wvpResult);
});
result.onTimeout(()->{
msg.setData("timeout");
WVPResult<RecordInfo> 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))

View File

@ -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<WVPResult<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
result.onTimeout(()->{
log.info("[点播等待超时] deviceId{}, channelId{}, ", deviceId, channelId);
// 释放rtpserver
WVPResult<StreamInfo> wvpResult = new WVPResult<>();
WVPResult<StreamContent> 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<StreamInfo> callback = (code, msg, streamInfo) -> {
WVPResult<StreamContent> 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);
}

View File

@ -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) {

View File

@ -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<String> queryPreset(@PathVariable String deviceId, @PathVariable String channelId) {
public DeferredResult<WVPResult<Object>> 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<String> result = new DeferredResult<String> (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<WVPResult<Object>> 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))

View File

@ -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);
}
}

View File

@ -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<Integer> channelIds;
@Schema(description = "所有通道, 和channelIds参数二选一")
private Boolean all;
}

View File

@ -20,8 +20,8 @@ public interface CommonGBChannelMapper {
@Insert(" <script>" +
"INSERT INTO wvp_device_channel (" +
"gb_device_id," +
" <if test='streamProxyId != null' > stream_proxy_id,</if>" +
" <if test='streamPushId != null' > stream_push_id,</if>" +
"data_type," +
"data_device_id," +
"create_time," +
"update_time," +
"gb_name," +
@ -59,8 +59,8 @@ public interface CommonGBChannelMapper {
"gb_svc_time_support_mode ) " +
"VALUES (" +
"#{gbDeviceId}, " +
" <if test='streamProxyId != null' > #{streamProxyId},</if>" +
" <if test='streamPushId != null' > #{streamPushId},</if>" +
"#{dataType}, " +
"#{dataDeviceId}, " +
"#{createTime}, " +
"#{updateTime}, " +
"#{gbName}, " +
@ -152,7 +152,7 @@ public interface CommonGBChannelMapper {
" SET gb_status = #{status}" +
" WHERE id = #{gbId}"+
" </script>"})
int updateStatusById(@Param("gbId") int gbId, @Param("status") int status);
int updateStatusById(@Param("gbId") int gbId, @Param("status") String status);
@Update("<script> " +
"<foreach collection='commonGBChannels' index='index' item='item' separator=';'> " +
@ -168,8 +168,8 @@ public interface CommonGBChannelMapper {
@Insert(" <script>" +
"INSERT INTO wvp_device_channel (" +
"gb_device_id," +
"stream_proxy_id, " +
"stream_push_id," +
"data_type, " +
"data_device_id," +
"create_time," +
"update_time," +
"gb_name," +
@ -207,7 +207,7 @@ public interface CommonGBChannelMapper {
"gb_svc_time_support_mode ) " +
"VALUES" +
"<foreach collection='commonGBChannels' index='index' item='item' separator=','> " +
"(#{item.gbDeviceId}, #{item.streamProxyId}, #{item.streamPushId},#{item.createTime},#{item.updateTime}," +
"(#{item.gbDeviceId}, #{item.dataType}, #{item.dataDeviceId},#{item.createTime},#{item.updateTime}," +
"#{item.gbName},#{item.gbManufacturer}, #{item.gbModel}," +
"#{item.gbOwner},#{item.gbCivilCode},#{item.gbBlock}, #{item.gbAddress}, #{item.gbParental}, #{item.gbParentId},#{item.gbSafetyWay}, " +
"#{item.gbRegisterWay},#{item.gbCertNum},#{item.gbCertifiable},#{item.gbErrCode},#{item.gbEndTime}, #{item.gbSecrecy},#{item.gbIpAddress}," +
@ -235,9 +235,9 @@ public interface CommonGBChannelMapper {
" gb_ptz_type = null, gb_position_type = null, gb_room_type = null, gb_use_type = null, gb_supply_light_type = null, " +
" gb_direction_type = null, gb_resolution = null, gb_business_group_id = null, gb_download_speed = null, gb_svc_space_support_mod = null, " +
" gb_svc_time_support_mode = null" +
" WHERE id = #{id} and device_db_id = #{gbDeviceDbId}"+
" WHERE id = #{id} and data_type = #{dataType} and data_device_id = #{dataDeviceId}"+
" </script>"})
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")
@ -250,21 +250,15 @@ public interface CommonGBChannelMapper {
"</script>"})
void batchDelete(List<CommonGBChannel> 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<CommonGBChannel> 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<CommonGBChannel> 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);
@ -313,18 +307,26 @@ public interface CommonGBChannelMapper {
" </script>"})
int removeCivilCodeByChannels(List<CommonGBChannel> channelList);
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
" SET gb_civil_code = null, civil_code = null" +
" WHERE id in "+
" <foreach collection='channelIdList' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
" </script>"})
int removeCivilCodeByChannelIds(List<Integer> channelIdList);
@SelectProvider(type = ChannelProvider.class, method = "queryByCivilCode")
List<CommonGBChannel> queryByCivilCode(@Param("civilCode") String civilCode);
@SelectProvider(type = ChannelProvider.class, method = "queryByGbDeviceIds")
List<CommonGBChannel> queryByGbDeviceIds(List<Integer> deviceIds);
List<CommonGBChannel> queryByGbDeviceIds(@Param("dataType") Integer dataType, List<Integer> deviceIds);
@Select(value = {" <script>" +
" select id from wvp_device_channel " +
" where channel_type = 0 and device_db_id in "+
" where channel_type = 0 and data_type = #{dataType} and data_device_id in "+
" <foreach collection='deviceIds' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
" </script>"})
List<Integer> queryByGbDeviceIdsForIds(List<Integer> deviceIds);
List<Integer> queryByGbDeviceIdsForIds(@Param("dataType") Integer dataType, List<Integer> deviceIds);
@SelectProvider(type = ChannelProvider.class, method = "queryByGroupList")
List<CommonGBChannel> queryByGroupList(List<Group> groupList);
@ -446,19 +448,20 @@ public interface CommonGBChannelMapper {
int updateCivilCodeByChannelList(@Param("civilCode") String civilCode, List<CommonGBChannel> channelList);
@SelectProvider(type = ChannelProvider.class, method = "queryListByStreamPushList")
List<CommonGBChannel> queryListByStreamPushList(List<StreamPush> streamPushList);
List<CommonGBChannel> queryListByStreamPushList(@Param("dataType") Integer dataType, List<StreamPush> streamPushList);
@Update(value = {" <script>" +
" <foreach collection='channels' item='item' separator=';' >" +
" UPDATE wvp_device_channel " +
" SET gb_longitude=#{item.gbLongitude}, gb_latitude=#{item.gbLatitude} " +
" WHERE stream_push_id IS NOT NULL AND gb_device_id=#{item.gbDeviceId} "+
" WHERE data_type = #{dataType} AND gb_device_id=#{item.gbDeviceId} "+
"</foreach>"+
" </script>"})
void updateGpsByDeviceIdForStreamPush(List<CommonGBChannel> channels);
void updateGpsByDeviceIdForStreamPush(@Param("dataType") Integer dataType, List<CommonGBChannel> channels);
@SelectProvider(type = ChannelProvider.class, method = "queryList")
List<CommonGBChannel> queryList(@Param("query") String query, @Param("online") Boolean online, @Param("hasRecordPlan") Boolean hasRecordPlan, @Param("channelType") Integer channelType);
List<CommonGBChannel> queryList(@Param("query") String query, @Param("online") Boolean online,
@Param("hasRecordPlan") Boolean hasRecordPlan, @Param("dataType") Integer dataType);
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
@ -493,9 +496,8 @@ public interface CommonGBChannelMapper {
@Select("<script>" +
" select " +
" 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.data_type,\n" +
" wdc.data_device_id,\n" +
" wdc.create_time,\n" +
" wdc.update_time,\n" +
" wdc.record_plan_id,\n" +
@ -542,12 +544,32 @@ public interface CommonGBChannelMapper {
" <if test='online == false'> AND coalesce(wdc.gb_status, wdc.status) = 'OFF'</if> " +
" <if test='hasLink == true'> AND wdc.record_plan_id = #{planId}</if> " +
" <if test='hasLink == false'> AND wdc.record_plan_id is null</if> " +
" <if test='channelType == 0'> AND wdc.device_db_id is not null</if> " +
" <if test='channelType == 1'> AND wdc.stream_push_id is not null</if> " +
" <if test='channelType == 2'> AND wdc.stream_proxy_id is not null</if> " +
" <if test='dataType != null'> AND wdc.data_type = #{dataType}</if> " +
"</script>")
List<CommonGBChannel> 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<CommonGBChannel> queryListByCivilCodeForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType);
@SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualCivilCode")
List<Integer> queryAllForUnusualCivilCode();
@SelectProvider(type = ChannelProvider.class, method = "queryListByParentForUnusual")
List<CommonGBChannel> queryListByParentForUnusual(@Param("query") String query, @Param("online") Boolean online, @Param("dataType")Integer dataType);
@SelectProvider(type = ChannelProvider.class, method = "queryAllForUnusualParent")
List<Integer> queryAllForUnusualParent();
@Update(value = {" <script>" +
" UPDATE wvp_device_channel " +
" SET gb_parent_id = null, gb_business_group_id = null, parent_id = null, business_group_id = null" +
" WHERE id in "+
" <foreach collection='channelIdsForClear' item='item' open='(' separator=',' close=')' > #{item}</foreach>" +
" </script>"})
void removeParentIdByChannelIds(List<Integer> channelIdsForClear);
}

View File

@ -21,13 +21,13 @@ public interface DeviceChannelMapper {
@Insert("<script> " +
"insert into wvp_device_channel " +
"(device_id, device_db_id, name, manufacturer, model, owner, civil_code, block, " +
"(device_id, data_type, data_device_id, name, manufacturer, model, owner, civil_code, block, " +
"address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, end_time, secrecy, " +
"ip_address, port, password, status, longitude, latitude, ptz_type, position_type, room_type, use_type, " +
"supply_light_type, direction_type, resolution, business_group_id, download_speed, svc_space_support_mod, " +
"svc_time_support_mode, create_time, update_time, sub_count, stream_id, has_audio, gps_time, stream_identification, channel_type) " +
"values " +
"(#{deviceId}, #{deviceDbId}, #{name}, #{manufacturer}, #{model}, #{owner}, #{civilCode}, #{block}, " +
"(#{deviceId}, #{dataType}, #{dataDeviceId}, #{name}, #{manufacturer}, #{model}, #{owner}, #{civilCode}, #{block}, " +
"#{address}, #{parental}, #{parentId}, #{safetyWay}, #{registerWay}, #{certNum}, #{certifiable}, #{errCode}, #{endTime}, #{secrecy}, " +
"#{ipAddress}, #{port}, #{password}, #{status}, #{longitude}, #{latitude}, #{ptzType}, #{positionType}, #{roomType}, #{useType}, " +
"#{supplyLightType}, #{directionType}, #{resolution}, #{businessGroupId}, #{downloadSpeed}, #{svcSpaceSupportMod}," +
@ -40,7 +40,8 @@ public interface DeviceChannelMapper {
"UPDATE wvp_device_channel " +
"SET update_time=#{updateTime}" +
", device_id=#{deviceId}" +
", device_db_id=#{deviceDbId}" +
", data_type=#{dataType}" +
", data_device_id=#{dataDeviceId}" +
", name=#{name}" +
", manufacturer=#{manufacturer}" +
", model=#{model}" +
@ -85,22 +86,22 @@ public interface DeviceChannelMapper {
int update(DeviceChannel channel);
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannels")
List<DeviceChannel> queryChannels(@Param("deviceDbId") int deviceDbId, @Param("civilCode") String civilCode,
List<DeviceChannel> queryChannels(@Param("dataDeviceId") int dataDeviceId, @Param("civilCode") String civilCode,
@Param("businessGroupId") String businessGroupId, @Param("parentChannelId") String parentChannelId,
@Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel,
@Param("online") Boolean online, @Param("channelIds") List<String> channelIds);
@SelectProvider(type = DeviceChannelProvider.class, method = "queryChannelsByDeviceDbId")
List<DeviceChannel> queryChannelsByDeviceDbId(@Param("deviceDbId") int deviceDbId);
List<DeviceChannel> queryChannelsByDeviceDbId(@Param("dataDeviceId") int dataDeviceId);
@Select(value = {" <script> " +
"select id from wvp_device_channel where device_db_id in " +
@Select("<script> " +
"select id from wvp_device_channel where data_type =1 and data_device_id in " +
" <foreach item='item' index='index' collection='deviceDbIds' open='(' separator=',' close=')'> #{item} </foreach>" +
" </script>"})
" </script>")
List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> 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 " +
" <if test='deviceId != null'> AND de.device_id = #{deviceId} </if> " +
" <if test='query != null'> AND (dc.device_id LIKE '%${query}%' OR dc.name LIKE '%${query}%' OR dc.name LIKE '%${query}%')</if> " +
" <if test='parentChannelId != null'> AND dc.parent_id=#{parentChannelId} </if> " +
@ -155,7 +156,7 @@ public interface DeviceChannelMapper {
"</foreach> </if>" +
"ORDER BY dc.device_id ASC" +
" </script>"})
List<DeviceChannelExtend> queryChannelsWithDeviceInfo(@Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List<String> channelIds);
List<DeviceChannelExtend> queryChannelsWithDeviceInfo( @Param("deviceId") String deviceId, @Param("parentChannelId") String parentChannelId, @Param("query") String query, @Param("hasSubChannel") Boolean hasSubChannel, @Param("online") Boolean online, @Param("channelIds") List<String> 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 " +
" <if test='query != null'> " +
"AND " +
"(COALESCE(dc.gb_device_id, dc.device_id) LIKE concat('%',#{query},'%') " +
@ -195,14 +196,14 @@ public interface DeviceChannelMapper {
@Insert("<script> " +
"insert into wvp_device_channel " +
"(device_id, device_db_id, name, manufacturer, model, owner, civil_code, block, " +
"(device_id, data_type, data_device_id, name, manufacturer, model, owner, civil_code, block, " +
"address, parental, parent_id, safety_way, register_way, cert_num, certifiable, err_code, end_time, secrecy, " +
"ip_address, port, password, status, longitude, latitude, ptz_type, position_type, room_type, use_type, " +
"supply_light_type, direction_type, resolution, business_group_id, download_speed, svc_space_support_mod, " +
"svc_time_support_mode, create_time, update_time, sub_count, stream_id, has_audio, gps_time, stream_identification, channel_type) " +
"values " +
"<foreach collection='addChannels' index='index' item='item' separator=','> " +
"(#{item.deviceId}, #{item.deviceDbId}, #{item.name}, #{item.manufacturer}, #{item.model}, #{item.owner}, #{item.civilCode}, #{item.block}, " +
"(#{item.deviceId}, #{item.dataType}, #{item.dataDeviceId}, #{item.name}, #{item.manufacturer}, #{item.model}, #{item.owner}, #{item.civilCode}, #{item.block}, " +
"#{item.address}, #{item.parental}, #{item.parentId}, #{item.safetyWay}, #{item.registerWay}, #{item.certNum}, #{item.certifiable}, #{item.errCode}, #{item.endTime}, #{item.secrecy}, " +
"#{item.ipAddress}, #{item.port}, #{item.password}, #{item.status}, #{item.longitude}, #{item.latitude}, #{item.ptzType}, #{item.positionType}, #{item.roomType}, #{item.useType}, " +
"#{item.supplyLightType}, #{item.directionType}, #{item.resolution}, #{item.businessGroupId}, #{item.downloadSpeed}, #{item.svcSpaceSupportMod}," +
@ -221,7 +222,8 @@ public interface DeviceChannelMapper {
" wvp_device_channel" +
" SET update_time=#{item.updateTime}" +
", device_id=#{item.deviceId}" +
", device_db_id=#{item.deviceDbId}" +
", data_type=#{item.dataType}" +
", data_device_id=#{item.dataDeviceId}" +
", name=#{item.name}" +
", manufacturer=#{item.manufacturer}" +
", model=#{item.model}" +
@ -273,7 +275,8 @@ public interface DeviceChannelMapper {
" wvp_device_channel" +
" SET update_time=#{item.updateTime}" +
", device_id=#{item.deviceId}" +
", device_db_id=#{item.deviceDbId}" +
", data_type=#{item.dataType}" +
", data_device_id=#{item.dataDeviceId}" +
", name=#{item.name}" +
", manufacturer=#{item.manufacturer}" +
", model=#{item.model}" +
@ -313,7 +316,7 @@ public interface DeviceChannelMapper {
", gps_time=#{item.gpsTime}" +
", stream_identification=#{item.streamIdentification}" +
", channel_type=#{item.channelType}" +
" 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}" +
"</foreach>" +
"</script>"})
int batchUpdateForNotify(List<DeviceChannel> 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 = {" <script>" +
" UPDATE wvp_device_channel " +
@ -338,7 +341,7 @@ public interface DeviceChannelMapper {
@Select("select " +
" id,\n" +
" device_db_id,\n" +
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" sub_count,\n" +
@ -381,11 +384,11 @@ public interface DeviceChannelMapper {
" download_speed,\n" +
" svc_space_support_mod,\n" +
" svc_time_support_mode\n" +
" from wvp_device_channel where device_db_id = #{deviceDbId}")
List<DeviceChannel> queryAllChannelsForRefresh(@Param("deviceDbId") int deviceDbId);
" from wvp_device_channel where data_type = 1 and data_device_id = #{dataDeviceId}")
List<DeviceChannel> queryAllChannelsForRefresh(@Param("dataDeviceId") int dataDeviceId);
@Select("select de.* from wvp_device de left join wvp_device_channel dc on de.device_id = dc.device_id where dc.device_id=#{channelId}")
List<Device> getDeviceByChannelDeviceId(String channelId);
@Select("select de.* from wvp_device de left join wvp_device_channel dc on de.device_id = dc.device_id where dc.data_type = 1 and dc.device_id=#{channelId}")
List<Device> getDeviceByChannelDeviceId(@Param("channelId") String channelId);
@Delete({"<script>" +
@ -397,7 +400,7 @@ public interface DeviceChannelMapper {
@Update({"<script>" +
"<foreach collection='channels' item='item' separator=';'>" +
"UPDATE wvp_device_channel SET status=#{item.status} WHERE device_id=#{item.deviceId}" +
"UPDATE wvp_device_channel SET status=#{item.status} WHERE data_type = #{item.dataType} and device_id=#{item.deviceId}" +
"</foreach>" +
"</script>"})
int batchUpdateStatus(List<DeviceChannel> channels);
@ -427,7 +430,7 @@ public interface DeviceChannelMapper {
"<if test='item.latitude != null'>, latitude=#{item.latitude}</if>" +
"<if test='item.gpsTime != null'>, gps_time=#{item.gpsTime}</if>" +
"<if test='item.id > 0'>WHERE id=#{item.id}</if>" +
"<if test='item.id == 0'>WHERE device_db_id=#{item.deviceDbId} AND device_id=#{item.deviceId}</if>" +
"<if test='item.id == 0'>WHERE data_type = #{item.dataType} and data_device_id=#{item.dataDeviceId} AND device_id=#{item.deviceId}</if>" +
"</foreach>" +
"</script>"})
void batchUpdatePosition(List<DeviceChannel> channelList);
@ -438,7 +441,7 @@ public interface DeviceChannelMapper {
@Select(value = {" <script>" +
" SELECT " +
" id,\n" +
" device_db_id,\n" +
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" sub_count,\n" +
@ -487,13 +490,13 @@ public interface DeviceChannelMapper {
DeviceChannel getOneForSource(@Param("id") int id);
@SelectProvider(type = DeviceChannelProvider.class, method = "getOneByDeviceId")
DeviceChannel getOneByDeviceId(@Param("deviceDbId") int deviceDbId, @Param("channelId") String channelId);
DeviceChannel getOneByDeviceId(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId);
@Select(value = {" <script>" +
" SELECT " +
" id,\n" +
" device_db_id,\n" +
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" sub_count,\n" +
@ -537,9 +540,9 @@ public interface DeviceChannelMapper {
" svc_space_support_mod,\n" +
" svc_time_support_mode\n" +
" from wvp_device_channel " +
" where device_db_id=#{deviceDbId} and coalesce(gb_device_id, device_id) = #{channelId}" +
" where data_type = 1 and data_device_id=#{dataDeviceId} and coalesce(gb_device_id, device_id) = #{channelId}" +
" </script>"})
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 {
"</script>")
void updateStreamGPS(List<GPSMsgInfo> 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 = {" <script>" +
" SELECT " +
" id,\n" +
" device_db_id,\n" +
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" sub_count,\n" +
@ -660,7 +663,7 @@ public interface DeviceChannelMapper {
" svc_space_support_mod,\n" +
" svc_time_support_mode\n" +
" from wvp_device_channel " +
" where device_db_id=#{deviceDbId} and device_id = #{channelId}" +
" where data_type = 1 and data_device_id=#{dataDeviceId} and device_id = #{channelId}" +
" </script>"})
DeviceChannel getOneBySourceChannelId(int deviceDbId, String channelId);
DeviceChannel getOneBySourceChannelId(@Param("dataDeviceId") int dataDeviceId, @Param("channelId") String channelId);
}

View File

@ -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 {
"<if test=\"onLine != null\">, on_line=#{onLine}</if>" +
"<if test=\"registerTime != null\">, register_time=#{registerTime}</if>" +
"<if test=\"keepaliveTime != null\">, keepalive_time=#{keepaliveTime}</if>" +
"<if test=\"keepaliveIntervalTime != null\">, keepalive_interval_time=#{keepaliveIntervalTime}</if>" +
"<if test=\"heartBeatInterval != null\">, heart_beat_interval=#{heartBeatInterval}</if>" +
"<if test=\"positionCapability != null\">, position_capability=#{positionCapability}</if>" +
"<if test=\"heartBeatCount != null\">, heart_beat_count=#{heartBeatCount}</if>" +
"<if test=\"expires != null\">, expires=#{expires}</if>" +
"<if test=\"serverId != null\">, server_id=#{serverId}</if>" +
"WHERE device_id=#{deviceId}"+
" </script>"})
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" +
"<if test=\"onLine != null\"> where de.on_line=${onLine}</if>"+
"<if test='online != null'> where de.on_line=${online}</if>"+
" order by de.create_time desc "+
" </script>"
)
List<Device> getDevices(Boolean onLine);
List<Device> 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<Device> 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<Device> getOnlineDevicesByServerId(@Param("serverId") String serverId);
@Select("SELECT " +
"id,"+
@ -247,9 +291,8 @@ public interface DeviceMapper {
@Update(value = {" <script>" +
"UPDATE wvp_device " +
"SET update_time=#{updateTime}, custom_name=#{name} , password=#{password}, stream_mode=#{streamMode}" +
", ip=#{ip}, sdp_ip=#{sdpIp}, port=#{port}, charset=#{charset}, subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}" +
", subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}" +
", subscribe_cycle_for_alarm=#{subscribeCycleForAlarm}, ssrc_check=#{ssrcCheck}, as_message_channel=#{asMessageChannel}" +
", ip=#{ip}, sdp_ip=#{sdpIp}, port=#{port}, charset=#{charset}" +
", ssrc_check=#{ssrcCheck}, as_message_channel=#{asMessageChannel}" +
", broadcast_push_after_ack=#{broadcastPushAfterAck}, geo_coord_sys=#{geoCoordSys}, media_server_id=#{mediaServerId}" +
" WHERE id=#{id}"+
" </script>"})
@ -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 "+
" <if test='status != null'> AND de.on_line=${status}</if>"+
@ -337,7 +383,7 @@ public interface DeviceMapper {
"</if> " +
" order by create_time desc "+
" </script>")
List<Device> getDeviceList(@Param("query") String query, @Param("status") Boolean status);
List<Device> 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 = {" <script>" +
" UPDATE wvp_device " +
" SET subscribe_cycle_for_catalog=#{subscribeCycleForCatalog}" +
" WHERE id=#{id}"+
" </script>"})
void updateSubscribeCatalog(Device device);
@Update(value = {" <script>" +
"UPDATE wvp_device " +
"SET subscribe_cycle_for_mobile_position=#{subscribeCycleForMobilePosition}, mobile_position_submission_interval=#{mobilePositionSubmissionInterval}" +
" WHERE id=#{id}"+
" </script>"})
void updateSubscribeMobilePosition(Device device);
}

View File

@ -58,16 +58,18 @@ public interface PlatformChannelMapper {
"where dc.channel_type = 0 and dc.channel_id = #{channelId} and pgc.platform_id=#{platformId}")
List<Device> 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<Integer> 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<Platform> queryParentPlatformByChannelId(@Param("channelId") String channelId);
@Select("<script>" +
" select " +
" wpgc.id ,\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.data_type ,\n" +
" wdc.data_device_id,\n" +
" wdc.create_time,\n" +
" wdc.update_time,\n" +
" wpgc.custom_device_id, \n" +
@ -149,19 +151,16 @@ public interface PlatformChannelMapper {
" <if test='online == false'> AND coalesce(wpgc.status, wdc.gb_status, wdc.status) = 'OFF'</if> " +
" <if test='hasShare == true'> AND wpgc.platform_id = #{platformId}</if> " +
" <if test='hasShare == false'> AND wpgc.platform_id is null</if> " +
" <if test='channelType == 0'> AND wdc.device_db_id is not null</if> " +
" <if test='channelType == 1'> AND wdc.stream_push_id is not null</if> " +
" <if test='channelType == 2'> AND wdc.stream_proxy_id is not null</if> " +
" <if test='dataType != null'> AND wdc.data_type = #{dataType}</if> " +
"</script>")
List<PlatformChannel> 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.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" +
@ -209,9 +208,8 @@ public interface PlatformChannelMapper {
@Select("<script>" +
" select " +
" 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.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" +
@ -260,9 +258,8 @@ public interface PlatformChannelMapper {
@Select("<script>" +
" select " +
" 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.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" +
@ -485,9 +482,8 @@ public interface PlatformChannelMapper {
@Select("<script>" +
" select " +
" 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.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" +

View File

@ -16,11 +16,11 @@ public interface PlatformMapper {
@Insert("INSERT INTO wvp_platform (enable, name, server_gb_id, server_gb_domain, server_ip, server_port,device_gb_id,device_ip,"+
" device_port,username,password,expires,keep_timeout,transport,character_set,ptz,rtcp,status,catalog_group, update_time," +
" create_time, as_message_channel, send_stream_ip, auto_push_channel, catalog_with_platform,catalog_with_group,catalog_with_region, "+
" civil_code,manufacturer,model,address,register_way,secrecy) " +
" civil_code,manufacturer,model,address,register_way,secrecy,server_id) " +
" VALUES (#{enable}, #{name}, #{serverGBId}, #{serverGBDomain}, #{serverIp}, #{serverPort}, #{deviceGBId}, #{deviceIp}, " +
" #{devicePort}, #{username}, #{password}, #{expires}, #{keepTimeout}, #{transport}, #{characterSet}, #{ptz}, #{rtcp}, #{status}, #{catalogGroup},#{updateTime}," +
" #{createTime}, #{asMessageChannel}, #{sendStreamIp}, #{autoPushChannel}, #{catalogWithPlatform}, #{catalogWithGroup},#{catalogWithRegion}, " +
" #{civilCode}, #{manufacturer}, #{model}, #{address}, #{registerWay}, #{secrecy})")
" #{civilCode}, #{manufacturer}, #{model}, #{address}, #{registerWay}, #{secrecy}, #{serverId})")
int add(Platform parentPlatform);
@Update("UPDATE wvp_platform " +
@ -55,6 +55,7 @@ public interface PlatformMapper {
" model=#{model}, " +
" address=#{address}, " +
" register_way=#{registerWay}, " +
" server_id=#{serverId}, " +
" secrecy=#{secrecy} " +
"WHERE id=#{id}")
int update(Platform parentPlatform);
@ -76,8 +77,8 @@ public interface PlatformMapper {
" </script>")
List<Platform> queryList(@Param("query") String query);
@Select("SELECT * FROM wvp_platform WHERE enable=#{enable} ")
List<Platform> getEnableParentPlatformList(boolean enable);
@Select("SELECT * FROM wvp_platform WHERE server_id=#{serverId} and enable=#{enable} ")
List<Platform> queryEnableParentPlatformList(@Param("serverId") String serverId, @Param("enable") boolean enable);
@Select("SELECT * FROM wvp_platform WHERE enable=true and as_message_channel=true")
List<Platform> 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<Platform> queryEnablePlatformList();
@Select("SELECT server_id FROM wvp_platform WHERE enable=true and server_id != #{serverId} group by server_id")
List<String> queryServerIdsWithEnableAndNotInServer(@Param("serverId") String serverId);
@Select("SELECT * FROM wvp_platform WHERE server_id = #{serverId}")
List<Platform> queryByServerId(@Param("serverId") String serverId);
}

View File

@ -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 {
" </script>")
Set<Region> queryNotShareRegionForPlatformByRegionList(Set<Region> allRegion, @Param("platformId") Integer platformId);
@Select(" <script>" +
" SELECT device_id " +
" from wvp_common_region" +
" where device_id in " +
" <foreach collection='civilCodePoList' item='item' open='(' separator=',' close=')' > #{item.code}</foreach>" +
" </script>")
Set<String> queryInCivilCodePoList(List<CivilCodePo> civilCodePoList);
}

View File

@ -12,9 +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" +
" data_type,\n" +
" data_device_id,\n" +
" create_time,\n" +
" update_time,\n" +
" record_plan_id,\n" +
@ -54,13 +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.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" +
@ -109,15 +151,10 @@ public class ChannelProvider {
return BASE_SQL + " where channel_type = 0 and id = #{gbId}";
}
public String queryByStreamPushId(Map<String, Object> params ){
return BASE_SQL + " where channel_type = 0 and stream_push_id = #{streamPushId}";
public String queryByDataId(Map<String, Object> params ){
return BASE_SQL + " where channel_type = 0 and data_type = #{dataType} and data_device_id = #{dataDeviceId}";
}
public String queryByStreamProxyId(Map<String, Object> params ){
return BASE_SQL + " where channel_type = 0 and stream_proxy_id = #{streamProxyId}";
}
public String queryListByCivilCode(Map<String, Object> params ){
StringBuilder sqlBuild = new StringBuilder();
sqlBuild.append(BASE_SQL);
@ -138,14 +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");
}
if (params.get("dataType") != null) {
sqlBuild.append(" AND data_type = #{dataType}");
}
return sqlBuild.toString();
}
@ -170,15 +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");
}
if (params.get("dataType") != null) {
sqlBuild.append(" AND data_type = #{dataType}");
}
return sqlBuild.toString();
}
@ -201,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();
}
@ -253,7 +270,7 @@ public class ChannelProvider {
public String queryByGbDeviceIds(Map<String, Object> 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<Integer> ids = (Collection<Integer>)params.get("deviceIds");
boolean first = true;
@ -356,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<StreamPush> ids = (Collection<StreamPush>)params.get("streamPushList");
boolean first = true;
for (StreamPush streamPush : ids) {
@ -391,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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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();
}
}

View File

@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> params ){
return getBaseSelectSql() + " where channel_type = 0 and id = #{gbId}";
}
public String queryByStreamPushId(Map<String, Object> params ){
return getBaseSelectSql() + " where channel_type = 0 and stream_push_id = #{streamPushId}";
}
public String queryByStreamProxyId(Map<String, Object> 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<String, Object> 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},'%') )")

View File

@ -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<CommonGBChannel> 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<CommonGBChannel> deviceChannels, String type) {
catalogEventPublish(platform, deviceChannels, type, true);
}
/**
*
* @param platformId
* @param deviceChannels
* @param type
*/
public void catalogEventPublish(Integer platformId, List<CommonGBChannel> deviceChannels, String type) {
public void catalogEventPublish(Platform platform, List<CommonGBChannel> 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<CommonGBChannel> 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);
}
}

View File

@ -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<String, MessageEvent<?>> subscribes = new ConcurrentHashMap<>();
private final DelayQueue<MessageEvent<?>> 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();
}
}

View File

@ -29,24 +29,24 @@ public class SipSubscribe {
private final DelayQueue<SipEvent> delayQueue = new DelayQueue<>();
@Scheduled(fixedDelay = 200) //每200毫秒执行
public void execute(){
if (delayQueue.isEmpty()) {
return;
}
try {
SipEvent take = delayQueue.take();
// 出现超时异常
if(take.getErrorEvent() != null) {
EventResult<Object> 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<Object> 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<EventObject>{

View File

@ -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;
}
}

View File

@ -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<RequestTimeoutEvent> {
@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(), "等待消息超时");
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -15,15 +15,15 @@ import java.util.concurrent.ConcurrentHashMap;
*/
@Slf4j
@Component
public class RecordEndEventListener implements ApplicationListener<RecordEndEvent> {
public class RecordInfoEventListener implements ApplicationListener<RecordInfoEvent> {
private Map<String, RecordEndEventHandler> handlerMap = new ConcurrentHashMap<>();
private final Map<String, RecordEndEventHandler> 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<RecordEndEven
/**
* 添加
* @param device
* @param channelId
* @param recordEndEventHandler
*/
public void addEndEventHandler(String device, String channelId, RecordEndEventHandler recordEndEventHandler) {
log.info("录像查询事件添加监听deviceId{}, channelId: {}", device, channelId);
@ -55,8 +52,6 @@ public class RecordEndEventListener implements ApplicationListener<RecordEndEven
}
/**
* 添加
* @param device
* @param channelId
*/
public void delEndEventHandler(String device, String channelId) {
log.info("录像查询事件移除监听deviceId{}, channelId: {}", device, channelId);

View File

@ -0,0 +1,56 @@
package com.genersoft.iot.vmp.gb28181.event.sip;
import com.genersoft.iot.vmp.service.bean.ErrorCallback;
import lombok.Data;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
@Data
public class MessageEvent<T> implements Delayed {
/**
* 超时时间(单位 毫秒)
*/
private long delay;
private String cmdType;
private String sn;
private String deviceId;
private String result;
private T t;
private ErrorCallback<T> 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 <T> MessageEvent<T> getInstance(String cmdType, String sn, String deviceId, Long delay, ErrorCallback<T> callback){
MessageEvent<T> 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;
}
}

View File

@ -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

View File

@ -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<CommonGBChannel> channels;
@Setter
@Getter
private String type;
@Setter
@Getter
private Integer platformId;
private Platform platform;
}

View File

@ -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<CatalogEvent> {
@Autowired
private IPlatformChannelService platformChannelService;
@Autowired
private IPlatformService platformService;
@Autowired
private ISIPCommanderForPlatform sipCommanderFroPlatform;
@ -46,11 +42,8 @@ public class CatalogEventLister implements ApplicationListener<CatalogEvent> {
Map<String, List<Platform>> parentPlatformMap = new HashMap<>();
Map<String, CommonGBChannel> 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;

View File

@ -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<DeviceChannel> queryChaneListByDeviceDbId(Integer deviceDbId);
List<Integer> queryChaneIdListByDeviceDbIds(List<Integer> deviceDbId);
void handlePtzCmd(@NotNull Integer dataDeviceId, @NotNull Integer gbId, Element rootElement, DeviceControlType type, ErrorCallback<String> callback);
void queryRecordInfo(Device device, DeviceChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> object);
void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> object);
}

View File

@ -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<Device> getAllOnlineDevice();
List<Device> getAllOnlineDevice(String serverId);
List<Device> 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<SyncStatus> devicesSync(Device device);
void deviceBasicConfig(Device device, BasicParam basicParam, ErrorCallback<String> callback);
void deviceConfigQuery(Device device, String channelId, String configType, ErrorCallback<Object> callback);
void teleboot(Device device);
void record(Device device, String channelId, String recordCmdStr, ErrorCallback<String> callback);
void guard(Device device, String guardCmdStr, ErrorCallback<String> callback);
void resetAlarm(Device device, String channelId, String alarmMethod, String alarmType, ErrorCallback<String> callback);
void iFrame(Device device, String channelId);
void homePosition(Device device, String channelId, Boolean enabled, Integer resetTime, Integer presetIndex, ErrorCallback<String> callback);
void dragZoomIn(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback<String> callback);
void dragZoomOut(Device device, String channelId, int length, int width, int midpointx, int midpointy, int lengthx, int lengthy, ErrorCallback<String> callback);
void deviceStatus(Device device, ErrorCallback<String> callback);
void updateDeviceHeartInfo(Device device);
void alarm(Device device, String startPriority, String endPriority, String alarmMethod, String alarmType, String startTime, String endTime, ErrorCallback<Object> callback);
void deviceInfo(Device device, ErrorCallback<Object> callback);
void queryPreset(Device device, String channelId, ErrorCallback<Object> callback);
}

View File

@ -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<String> callback);
void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback);
}

View File

@ -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<StreamInfo> callback);
void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> callback);
void play(CommonGBChannel channel, Platform platform, ErrorCallback<StreamInfo> callback);
void stopPlay(InviteSessionType type, CommonGBChannel channel, String stream);
void playGbDeviceChannel(CommonGBChannel channel, ErrorCallback<StreamInfo> callback);
void play(CommonGBChannel channel, Platform platform, Boolean record, ErrorCallback<StreamInfo> callback);
void playProxy(CommonGBChannel channel, ErrorCallback<StreamInfo> callback);
void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void stopPlayDeviceChannel(InviteSessionType type, CommonGBChannel channel, String stream);
void playProxy(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void stopPlayProxy(CommonGBChannel channel);
void playPush(CommonGBChannel channel, String platformDeviceId, String platformName, ErrorCallback<StreamInfo> callback);
void stopPlayPush(CommonGBChannel channel);
void pauseRtp(String streamId);
void resumeRtp(String streamId);
}

View File

@ -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<CommonGBChannel> queryList(int page, int count, String query, Boolean online, Boolean hasRecordPlan, Integer channelType);
void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> callback);
PageInfo<CommonGBChannel> queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType);
void clearChannelCivilCode(Boolean all, List<Integer> channelIds);
PageInfo<CommonGBChannel> queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType);
void clearChannelParent(Boolean all, List<Integer> channelIds);
}

View File

@ -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);
}

View File

@ -43,6 +43,8 @@ public interface IPlatformChannelService {
CommonGBChannel queryChannelByPlatformIdAndChannelId(Integer platformId, Integer channelId);
List<CommonGBChannel> queryChannelByPlatformIdAndChannelIds(Integer platformId, List<Integer> channelIds);
void checkRegionAdd(List<CommonGBChannel> channelList);
void checkRegionRemove(List<CommonGBChannel> channelList, List<Region> regionList);

View File

@ -69,25 +69,20 @@ public interface IPlatformService {
/**
* 向上级发送语音喊话的消息
* @param platform 平台
* @param channelId 通道
* @param hookEvent hook事件
* @param errorEvent 信令错误事件
* @param timeoutCallback 超时事件
*/
void broadcastInvite(Platform platform, CommonGBChannel channelId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
void broadcastInvite(Platform platform, CommonGBChannel channel, String sourceId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException;
/**
* 语音喊话回复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<Platform> queryEnablePlatformList();
List<Platform> queryEnablePlatformList(String serverId);
void delete(Integer platformId, CommonCallback<Object> callback);
}

View File

@ -25,6 +25,8 @@ public interface IPlayService {
SSRCInfo play(MediaServer mediaServerItem, String deviceId, String channelId, String ssrc, ErrorCallback<StreamInfo> callback);
void play(Device device, DeviceChannel channel, ErrorCallback<StreamInfo> 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<StreamInfo> callback);
void play(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
void stop(InviteSessionType inviteSessionType, CommonGBChannel channel, String stream);
void playBack(CommonGBChannel channel, Long startTime, Long stopTime, ErrorCallback<StreamInfo> callback);
void download(CommonGBChannel channel, Long startTime, Long stopTime, Integer downloadSpeed, ErrorCallback<StreamInfo> callback);
}

View File

@ -36,4 +36,8 @@ public interface IRegionService {
boolean batchAdd(List<Region> regionList);
List<Region> getPath(String deviceId);
String getDescription(String civilCode);
void addByCivilCode(String civilCode);
}

View File

@ -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

View File

@ -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<String, SynchronousQueue<RecordInfo>> topicSubscribers = new ConcurrentHashMap<>();
/**
* 监听录像查询结束事件
*/
@Async("taskExecutor")
@org.springframework.context.event.EventListener
public void onApplicationEvent(RecordInfoEndEvent event) {
SynchronousQueue<RecordInfo> 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<DeviceChannel> channels) {
@ -84,7 +125,7 @@ public class DeviceChannelServiceImpl implements IDeviceChannelService {
List<DeviceChannel> 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<String> 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<String,DeviceChannel> 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<String, Integer> 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<Integer> 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<Platform> 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(deviceChannel.getDeviceDbId() + 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<RecordInfo> 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<RecordInfo> 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<RecordInfo> 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);
}
}

View File

@ -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<SsrcTransaction> 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<Boolean> 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<Boolean> 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<Device> getAllOnlineDevice() {
return deviceMapper.getOnlineDevices();
public List<Device> getAllOnlineDevice(String serverId) {
return deviceMapper.getOnlineDevicesByServerId(serverId);
}
@Override
public List<Device> 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<String> 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<Device> all = deviceMapper.getDeviceList(query, status);
List<Device> 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<SyncStatus> 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<SyncStatus> 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<SyncStatus> wvpResult = new WVPResult<>();
wvpResult.setCode(0);
wvpResult.setMsg("开始同步");
return wvpResult;
}
@Override
public void deviceBasicConfig(Device device, BasicParam basicParam, ErrorCallback<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<Object> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<String> 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("<DragZoomIn>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomIn>\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<String> 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("<DragZoomOut>\r\n");
cmdXml.append("<Length>" + length+ "</Length>\r\n");
cmdXml.append("<Width>" + width+ "</Width>\r\n");
cmdXml.append("<MidPointX>" + midpointx+ "</MidPointX>\r\n");
cmdXml.append("<MidPointY>" + midpointy+ "</MidPointY>\r\n");
cmdXml.append("<LengthX>" + lengthx+ "</LengthX>\r\n");
cmdXml.append("<LengthY>" + lengthy+ "</LengthY>\r\n");
cmdXml.append("</DragZoomOut>\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<String> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<Object> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<String> 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<Object> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<Object> 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<Object> callback) {
if (!userSetting.getServerId().equals(device.getServerId())) {
WVPResult<Object> 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());
}
}
}

View File

@ -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<String> callback) {
log.info("[通用通道] 云台控制, 通道: {}", channel.getGbId());
}
@Override
public void preset(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] 预置位, 通道: {}", channel.getGbId());
}
@Override
public void fi(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
log.info("[通用通道] FI指令 通道: {}", channel.getGbId());
}
@Override
public void tour(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
}
@Override
public void scan(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
}
@Override
public void auxiliary(CommonGBChannel channel, FrontEndControlCodeForPTZ frontEndControlCode, ErrorCallback<String> callback) {
}
}

View File

@ -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<StreamInfo> callback) {
if (channel == null || inviteInfo == null || callback == null) {
public void start(CommonGBChannel channel, InviteMessageInfo inviteInfo, Platform platform, ErrorCallback<StreamInfo> 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<StreamInfo> 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<StreamInfo> 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<StreamInfo> callback){
public void playGbDeviceChannel(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> 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<StreamInfo> 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<StreamInfo> 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<StreamInfo> 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<StreamInfo> 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<StreamInfo> callback){
try {
@ -172,4 +238,6 @@ public class GbChannelPlayServiceImpl implements IGbChannelPlayService {
callback.run(Response.BUSY_HERE, "busy here", null);
}
}
}

View File

@ -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<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds);
List<CommonGBChannel> 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<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds);
List<CommonGBChannel> 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<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds);
List<CommonGBChannel> 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<Integer> deviceIds) {
List<CommonGBChannel> channelList = commonGBChannelMapper.queryByGbDeviceIds(deviceIds);
List<CommonGBChannel> 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<CommonGBChannel> queryListByStreamPushList(List<StreamPush> streamPushList) {
return commonGBChannelMapper.queryListByStreamPushList(streamPushList);
return commonGBChannelMapper.queryListByStreamPushList(ChannelDataType.STREAM_PUSH.value, streamPushList);
}
@Override
public void updateGpsByDeviceIdForStreamPush(List<CommonGBChannel> channels) {
commonGBChannelMapper.updateGpsByDeviceIdForStreamPush(channels);
commonGBChannelMapper.updateGpsByDeviceIdForStreamPush(ChannelDataType.STREAM_PUSH.value, channels);
}
@Override
@ -726,4 +731,70 @@ public class GbChannelServiceImpl implements IGbChannelService {
List<CommonGBChannel> all = commonGBChannelMapper.queryList(query, online, hasRecordPlan, channelType);
return new PageInfo<>(all);
}
@Override
public void queryRecordInfo(CommonGBChannel channel, String startTime, String endTime, ErrorCallback<RecordInfo> 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<CommonGBChannel> queryListByCivilCodeForUnusual(int page, int count, String query, Boolean online, Integer channelType) {
PageHelper.startPage(page, count);
if (query != null) {
query = query.replaceAll("/", "//")
.replaceAll("%", "/%")
.replaceAll("_", "/_");
}
List<CommonGBChannel> all = commonGBChannelMapper.queryListByCivilCodeForUnusual(query, online, channelType);
return new PageInfo<>(all);
}
@Override
public void clearChannelCivilCode(Boolean all, List<Integer> channelIds) {
List<Integer> channelIdsForClear;
if (all != null && all) {
channelIdsForClear = commonGBChannelMapper.queryAllForUnusualCivilCode();
}else {
channelIdsForClear = channelIds;
}
commonGBChannelMapper.removeCivilCodeByChannelIds(channelIdsForClear);
}
@Override
public PageInfo<CommonGBChannel> queryListByParentForUnusual(int page, int count, String query, Boolean online, Integer channelType) {
PageHelper.startPage(page, count);
if (query != null) {
query = query.replaceAll("/", "//")
.replaceAll("%", "/%")
.replaceAll("_", "/_");
}
List<CommonGBChannel> all = commonGBChannelMapper.queryListByParentForUnusual(query, online, channelType);
return new PageInfo<>(all);
}
@Override
public void clearChannelParent(Boolean all, List<Integer> channelIds) {
List<Integer> channelIdsForClear;
if (all != null && all) {
channelIdsForClear = commonGBChannelMapper.queryAllForUnusualParent();
}else {
channelIdsForClear = channelIds;
}
commonGBChannelMapper.removeParentIdByChannelIds(channelIdsForClear);
}
}

View File

@ -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<Group> 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<Group> 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);
}

View File

@ -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<String, List<ErrorCallback<StreamInfo>>> inviteErrorCallbackMap = new ConcurrentHashMap<>();

View File

@ -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<Preset> queryPresetList(String deviceId, String channelDeviceId) {
return Collections.emptyList();

View File

@ -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<CommonGBChannel> 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<CommonGBChannel> 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<Integer> deviceIds) {
List<Integer> channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(deviceIds);
List<Integer> channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(ChannelDataType.GB28181.value, deviceIds);
addChannels(platformId, channelList);
}
@Override
@Transactional
public void removeChannelByDevice(Integer platformId, List<Integer> deviceIds) {
List<Integer> channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(deviceIds);
List<Integer> channelList = commonGBChannelMapper.queryByGbDeviceIdsForIds(ChannelDataType.GB28181.value, deviceIds);
removeChannels(platformId, channelList);
}
@Transactional
public int removeChannelList(Integer platformId, List<CommonGBChannel> 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<CommonGBChannel> queryChannelByPlatformIdAndChannelIds(Integer platformId, List<Integer> channelIds) {
return platformChannelMapper.queryShare(platformId, channelIds);
}
}

View File

@ -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<String> 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<Platform> 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());
@ -484,7 +578,7 @@ public class PlatformServiceImpl implements IPlatformService {
}
@Override
public void broadcastInvite(Platform platform, CommonGBChannel channel, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
public void broadcastInvite(Platform platform, CommonGBChannel channel, String sourceId, MediaServer mediaServerItem, HookSubscribe.Event hookEvent,
SipSubscribe.Event errorEvent, InviteTimeOutCallback timeoutCallback) throws InvalidArgumentException, ParseException, SipException {
if (mediaServerItem == null) {
@ -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,19 +647,19 @@ 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());
}
}
}, userSetting.getPlayTimeout());
commanderForPlatform.broadcastInviteCmd(platform, channel, mediaServerItem, ssrcInfo, (hookData)->{
commanderForPlatform.broadcastInviteCmd(platform, channel,sourceId, mediaServerItem, ssrcInfo, (hookData)->{
log.info("[国标级联] 发起语音喊话 收到上级推流 deviceId: {}, channelId: {}", platform.getServerGBId(), channel.getGbDeviceId());
dynamicTask.stop(timeOutTaskKey);
// hook响应
@ -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<Platform> queryEnablePlatformList() {
return platformMapper.queryEnablePlatformList();
public List<Platform> queryEnablePlatformList(String serverId) {
return platformMapper.queryEnableParentPlatformList(serverId,true);
}
@Override

View File

@ -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<StreamInfo> 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<StreamInfo> 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<StreamInfo> callback) {
private SSRCInfo play(MediaServer mediaServerItem, Device device, DeviceChannel channel, String ssrc, Boolean record,
ErrorCallback<StreamInfo> 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<StreamInfo> 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<StreamInfo> callback) {
Device device = deviceService.getDevice(channel.getGbDeviceDbId());
public void play(CommonGBChannel channel, Boolean record, ErrorCallback<StreamInfo> 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");

View File

@ -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<CivilCodePo> 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<CivilCodePo> civilCodePoList = CivilCodeUtil.INSTANCE.getAllParentCode(civilCode);
civilCodePoList.add(civilCodePo);
Set<String> 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();
}
}
}

View File

@ -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<String, RecordInfo> data = new ConcurrentHashMap<>();
@Autowired
private DeferredResultHolder deferredResultHolder;
@Autowired
private RecordEndEventListener recordEndEventListener;
public int put(String deviceId,String channelId, String sn, int sumNum, List<RecordItem> 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<String> 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);
}
}

View File

@ -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());
}
}

View File

@ -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<Device> deviceList = deviceService.getAllOnlineDevice();
List<Device> 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());
}
});

View File

@ -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<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>();
private static Map<String, ISIPResponseProcessor> responseProcessorMap = new ConcurrentHashMap<>();
private static ITimeoutProcessor timeoutProcessor;
private static final Map<String, ISIPRequestProcessor> requestProcessorMap = new ConcurrentHashMap<>();
private static final Map<String, ISIPResponseProcessor> 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<ResponseEvent> 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<ResponseEvent> eventResult = new SipSubscribe.EventResult<>(responseEvent);
sipEvent.getErrorEvent().response(eventResult);
}
sipSubscribe.removeSubscribe(callIdHeader.getCallId());
sipSubscribe.removeSubscribe(callIdHeader.getCallId() + cSeqHeader.getSeqNumber());
}
}
}

View File

@ -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)) {

View File

@ -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<String, Map<String, DeferredResultEx>> map = new ConcurrentHashMap<>();

View File

@ -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<String> 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<String> 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<String> 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<String> 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<String> callback) throws InvalidArgumentException, SipException, ParseException;
/**
* 查询设备状态
*
* @param device 视频设备
*/
void deviceStatusQuery(Device device, SipSubscribe.Event errorEvent) throws InvalidArgumentException, SipException, ParseException;
void deviceStatusQuery(Device device, ErrorCallback<String> 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<Object> 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<Object> 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<Object> 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<Object> 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<String> 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;

View File

@ -140,13 +140,13 @@ public interface ISIPCommanderForPlatform {
* @param sendRtpItem
* @return
*/
void sendMediaStatusNotify(Platform platform, SendRtpInfo sendRtpItem) throws SipException, InvalidArgumentException, ParseException;
void sendMediaStatusNotify(Platform platform, SendRtpInfo sendRtpItem, CommonGBChannel channel) throws SipException, InvalidArgumentException, ParseException;
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, MediaServer mediaServerItem,
void broadcastInviteCmd(Platform platform, CommonGBChannel channel, String sourceId, MediaServer mediaServerItem,
SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException;

View File

@ -312,12 +312,12 @@ public class SIPRequestHeaderPlarformProvider {
return request;
}
public Request createInviteRequest(Platform platform, String channelId, String content, String viaTag, String fromTag, String ssrc, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException {
public Request createInviteRequest(Platform platform,String sourceId, String channelId, String content, String viaTag, String fromTag, String ssrc, CallIdHeader callIdHeader) throws PeerUnavailableException, ParseException, InvalidArgumentException {
Request request = null;
//请求行
String platformHostAddress = platform.getServerIp() + ":" + platform.getServerPort();
String localHostAddress = sipLayer.getLocalIp(platform.getDeviceIp())+":"+ platform.getDevicePort();
SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
SipURI requestLine = SipFactory.getInstance().createAddressFactory().createSipURI(sourceId, platformHostAddress);
//via
ArrayList<ViaHeader> viaHeaders = new ArrayList<ViaHeader>();
ViaHeader viaHeader = SipFactory.getInstance().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getDevicePort(), platform.getTransport(), viaTag);
@ -329,7 +329,7 @@ public class SIPRequestHeaderPlarformProvider {
Address fromAddress = SipFactory.getInstance().createAddressFactory().createAddress(fromSipURI);
FromHeader fromHeader = SipFactory.getInstance().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记否则无法创建会话无法回应ack
//to
SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(channelId, platformHostAddress);
SipURI toSipURI = SipFactory.getInstance().createAddressFactory().createSipURI(sourceId, platformHostAddress);
Address toAddress = SipFactory.getInstance().createAddressFactory().createAddress(toSipURI);
ToHeader toHeader = SipFactory.getInstance().createHeaderFactory().createToHeader(toAddress,null);
@ -345,7 +345,7 @@ public class SIPRequestHeaderPlarformProvider {
Address concatAddress = SipFactory.getInstance().createAddressFactory().createAddress(SipFactory.getInstance().createAddressFactory().createSipURI(sipConfig.getId(),localHostAddress));
request.addHeader(SipFactory.getInstance().createHeaderFactory().createContactHeader(concatAddress));
// Subject
SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", sipConfig.getId(), ssrc, channelId, 0));
SubjectHeader subjectHeader = SipFactory.getInstance().createHeaderFactory().createSubjectHeader(String.format("%s:%s,%s:%s", sourceId, ssrc, channelId, 0));
request.addHeader(subjectHeader);
ContentTypeHeader contentTypeHeader = SipFactory.getInstance().createHeaderFactory().createContentTypeHeader("APPLICATION", "SDP");
request.setContent(content, contentTypeHeader);

View File

@ -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("</Info>\r\n");
ptzXml.append("</Control>\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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
if (ObjectUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
@ -692,10 +642,14 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<RecordCmd>" + recordCmdStr + "</RecordCmd>\r\n");
cmdXml.append("</Control>\r\n");
MessageEvent<String> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
cmdXml.append("<GuardCmd>" + guardCmdStr + "</GuardCmd>\r\n");
cmdXml.append("</Control>\r\n");
MessageEvent<String> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
cmdXml.append("<AlarmCmd>ResetAlarm</AlarmCmd>\r\n");
if (!ObjectUtils.isEmpty(alarmMethod) || !ObjectUtils.isEmpty(alarmType)) {
@ -777,10 +741,14 @@ public class SIPCommander implements ISIPCommander {
}
cmdXml.append("</Control>\r\n");
MessageEvent<String> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceControl</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
if (ObjectUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
channelId = device.getDeviceId();
}
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
cmdXml.append("<HomePosition>\r\n");
if (enabled) {
cmdXml.append("<Enabled>1</Enabled>\r\n");
@ -846,10 +816,14 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("</HomePosition>\r\n");
cmdXml.append("</Control>\r\n");
MessageEvent<String> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Control>\r\n");
cmdXml.append("<CmdType>DeviceConfig</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
String channelId = basicParam.getChannelId();
if (ObjectUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
channelId = device.getDeviceId();
}
cmdXml.append("<DeviceID>" + channelId + "</DeviceID>\r\n");
cmdXml.append("<BasicParam>\r\n");
if (!ObjectUtils.isEmpty(name)) {
cmdXml.append("<Name>" + name + "</Name>\r\n");
if (!ObjectUtils.isEmpty(basicParam.getName())) {
cmdXml.append("<Name>" + basicParam.getName() + "</Name>\r\n");
}
if (NumericUtil.isInteger(expiration)) {
if (Integer.valueOf(expiration) > 0) {
cmdXml.append("<Expiration>" + expiration + "</Expiration>\r\n");
if (NumericUtil.isInteger(basicParam.getExpiration())) {
if (Integer.parseInt(basicParam.getExpiration()) > 0) {
cmdXml.append("<Expiration>" + basicParam.getExpiration() + "</Expiration>\r\n");
}
}
if (NumericUtil.isInteger(heartBeatInterval)) {
if (Integer.valueOf(heartBeatInterval) > 0) {
cmdXml.append("<HeartBeatInterval>" + heartBeatInterval + "</HeartBeatInterval>\r\n");
}
if (basicParam.getHeartBeatInterval() != null && basicParam.getHeartBeatInterval() > 0) {
cmdXml.append("<HeartBeatInterval>" + basicParam.getHeartBeatInterval() + "</HeartBeatInterval>\r\n");
}
if (NumericUtil.isInteger(heartBeatCount)) {
if (Integer.valueOf(heartBeatCount) > 0) {
cmdXml.append("<HeartBeatCount>" + heartBeatCount + "</HeartBeatCount>\r\n");
}
if (basicParam.getHeartBeatCount() != null && basicParam.getHeartBeatCount() > 0) {
cmdXml.append("<HeartBeatCount>" + basicParam.getHeartBeatCount() + "</HeartBeatCount>\r\n");
}
cmdXml.append("</BasicParam>\r\n");
cmdXml.append("</Control>\r\n");
MessageEvent<String> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
catalogXml.append("<Query>\r\n");
catalogXml.append("<CmdType>DeviceStatus</CmdType>\r\n");
catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
catalogXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
catalogXml.append("<SN>" + sn + "</SN>\r\n");
catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
catalogXml.append("</Query>\r\n");
MessageEvent<String> 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<Object> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
catalogXml.append("<Query>\r\n");
catalogXml.append("<CmdType>DeviceInfo</CmdType>\r\n");
catalogXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
catalogXml.append("<CmdType>" + cmdType +"</CmdType>\r\n");
catalogXml.append("<SN>" + sn + "</SN>\r\n");
catalogXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
catalogXml.append("</Query>\r\n");
MessageEvent<Object> 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<Object> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>Alarm</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
if (!ObjectUtils.isEmpty(startPriority)) {
cmdXml.append("<StartAlarmPriority>" + startPriority + "</StartAlarmPriority>\r\n");
@ -1075,10 +1064,14 @@ public class SIPCommander implements ISIPCommander {
}
cmdXml.append("</Query>\r\n");
MessageEvent<Object> 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<Object> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>ConfigDownload</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
if (ObjectUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
@ -1105,10 +1100,16 @@ public class SIPCommander implements ISIPCommander {
cmdXml.append("<ConfigType>" + configType + "</ConfigType>\r\n");
cmdXml.append("</Query>\r\n");
MessageEvent<Object> 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<Object> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
cmdXml.append("<Query>\r\n");
cmdXml.append("<CmdType>PresetQuery</CmdType>\r\n");
cmdXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
cmdXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
cmdXml.append("<SN>" + sn + "</SN>\r\n");
if (ObjectUtils.isEmpty(channelId)) {
cmdXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
@ -1132,9 +1136,14 @@ public class SIPCommander implements ISIPCommander {
}
cmdXml.append("</Query>\r\n");
MessageEvent<Object> 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<String> 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("<?xml version=\"1.0\" encoding=\"" + charset + "\"?>\r\n");
dragXml.append("<Control>\r\n");
dragXml.append("<CmdType>DeviceControl</CmdType>\r\n");
dragXml.append("<SN>" + (int) ((Math.random() * 9 + 1) * 100000) + "</SN>\r\n");
dragXml.append("<CmdType>" + cmdType + "</CmdType>\r\n");
dragXml.append("<SN>" + sn + "</SN>\r\n");
if (ObjectUtils.isEmpty(channelId)) {
dragXml.append("<DeviceID>" + device.getDeviceId() + "</DeviceID>\r\n");
} else {
@ -1289,8 +1301,10 @@ public class SIPCommander implements ISIPCommander {
dragXml.append(cmdString);
dragXml.append("</Control>\r\n");
MessageEvent<String> 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;

View File

@ -59,9 +59,6 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
@Autowired
private IMediaServerService mediaServerService;
@Autowired
private SipSubscribe sipSubscribe;
@Autowired
private SipLayer sipLayer;
@ -599,24 +596,23 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
}
@Override
public void sendMediaStatusNotify(Platform parentPlatform, SendRtpInfo sendRtpItem) throws SipException, InvalidArgumentException, ParseException {
if (sendRtpItem == null || parentPlatform == null) {
public void sendMediaStatusNotify(Platform parentPlatform, SendRtpInfo sendRtpInfo, CommonGBChannel channel) throws SipException, InvalidArgumentException, ParseException {
if (channel == null || parentPlatform == null) {
return;
}
String characterSet = parentPlatform.getCharacterSet();
StringBuffer mediaStatusXml = new StringBuffer(200);
mediaStatusXml.append("<?xml version=\"1.0\" encoding=\"" + characterSet + "\"?>\r\n")
.append("<Notify>\r\n")
.append("<CmdType>MediaStatus</CmdType>\r\n")
.append("<SN>" + (int)((Math.random()*9+1)*100000) + "</SN>\r\n")
.append("<DeviceID>" + sendRtpItem.getChannelId() + "</DeviceID>\r\n")
.append("<DeviceID>" + channel.getGbDeviceId() + "</DeviceID>\r\n")
.append("<NotifyType>121</NotifyType>\r\n")
.append("</Notify>\r\n");
SIPRequest messageRequest = (SIPRequest)headerProviderPlatformProvider.createMessageRequest(parentPlatform, mediaStatusXml.toString(),
sendRtpItem);
sendRtpInfo);
sipSender.transmitRequest(parentPlatform.getDeviceIp(),messageRequest);
@ -647,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);
@ -661,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);
@ -691,7 +687,7 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
}
@Override
public void broadcastInviteCmd(Platform platform, CommonGBChannel channel, MediaServer mediaServerItem,
public void broadcastInviteCmd(Platform platform, CommonGBChannel channel,String sourceId, MediaServer mediaServerItem,
SSRCInfo ssrcInfo, HookSubscribe.Event event, SipSubscribe.Event okEvent,
SipSubscribe.Event errorEvent) throws ParseException, SipException, InvalidArgumentException {
String stream = ssrcInfo.getStream();
@ -712,8 +708,9 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
StringBuffer content = new StringBuffer(200);
content.append("v=0\r\n");
content.append("o=" + channel.getGbDeviceId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
content.append("o=" + platform.getDeviceGBId() + " 0 0 IN IP4 " + sdpIp + "\r\n");
content.append("s=Play\r\n");
content.append("u=" + channel.getGbDeviceId() + ":0\r\n");
content.append("c=IN IP4 " + sdpIp + "\r\n");
content.append("t=0 0\r\n");
@ -738,21 +735,22 @@ public class SIPCommanderForPlatform implements ISIPCommanderForPlatform {
content.append("y=" + ssrcInfo.getSsrc() + "\r\n");//ssrc
// f字段:f= v/编码格式/分辨率/帧率/码率类型/码率大小a/编码格式/码率大小/采样率
content.append("f=v/////a/1/8/1\r\n");
content.append("f=v/2/5/25/1/4096a/1/8/1\r\n");
CallIdHeader callIdHeader = sipSender.getNewCallIdHeader(sipLayer.getLocalIp(platform.getDeviceIp()), platform.getTransport());
Request request = headerProviderPlatformProvider.createInviteRequest(platform, channel.getGbDeviceId(),
Request request = headerProviderPlatformProvider.createInviteRequest(platform, sourceId, channel.getGbDeviceId(),
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);
});

Some files were not shown because too many files have changed in this diff Show More