| ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java | ●●●●● patch | view | raw | blame | history | |
| ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java | ●●●●● patch | view | raw | blame | history | |
| ard-quartz/pom.xml | ●●●●● patch | view | raw | blame | history | |
| ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java | ●●●●● patch | view | raw | blame | history | |
| ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java | ●●●●● patch | view | raw | blame | history | |
| ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java | ●●●●● patch | view | raw | blame | history |
ard-device/src/main/java/com/ard/device/camera/service/impl/ArdCameraServiceImpl.java
@@ -373,87 +373,4 @@ redisService.setCacheObject(getCacheKey(camera.getId()), camera); } /** * 同步设备通道与本地通道库信息 * * @author 刘苏义 * @date 2024/8/22 14:37 */ @Scheduled(fixedDelay = 5000) public void syncChannel() { try { log.debug("定时执行同步通道任务"); List<ArdCamera> ardCameraList = this.selectArdCameraList(new ArdCamera()); if (!ardCameraList.isEmpty()) { ardCameraList .forEach(ardCamera -> { //SDK获取实际通道 List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera); //数据库获取通道 ArdChannel ardChannel = new ArdChannel(); ardChannel.setDeviceId(ardCamera.getId()); List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel); //同步通道 asyncChannel(ardChannelListDb, ardChannelListSDK); }); } } catch (Exception ex) { log.error("定时执行同步通道任务异常:{}", ex.getMessage()); } } /** * 定时执行登录失败相机重新登录 * * @author 刘苏义 * @date 2024/8/22 14:37 */ @Scheduled(fixedDelay = 10000) public void failedReconnect() { try { log.debug("定时执行失败相机重连任务"); // 从数据库取全部设备 List<ArdCamera> cameraList = selectArdCameraList(new ArdCamera()); cameraList.stream() // 只处理登录失败或离线的设备 .filter(camera -> camera.getLoginId() == null || camera.getLoginId() < 0 || "0".equals(camera.getState())) .forEach(camera -> { log.info("尝试重新登录设备 {}:{}", camera.getIp(), camera.getPort()); cameraSDKService.login(camera); }); } catch (Exception ex) { log.error("定时执行失败相机重连任务异常:{}", ex.getMessage()); } } /** * 同步相机在线状态 * 刘苏义 * 2023/10/8 14:54:41 */ @Scheduled(fixedDelay = 5000) public void cameraState() { try { log.debug("定时执行同步相机在线状态任务"); //调用查询方法 List<ArdCamera> ardCameraList = selectArdCameraList(new ArdCamera()); ardCameraList .forEach(camera -> { boolean onLineNew = cameraSDKService.isOnLine(camera); boolean onLineOld = "1".equals(camera.getState()); if (onLineNew != onLineOld) { if (onLineNew) { camera.setState("1"); } else { camera.setState("0"); } camera.setUpdateTime(DateUtils.getNowDate()); ardCameraMapper.updateArdCamera(camera); } }); } catch (Exception ex) { log.error("同步相机在线状态异常:{}", ex.getMessage()); } } } ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -30,16 +30,9 @@ @Slf4j @Service public class ArdChannelServiceImpl implements IArdChannelService { // @Resource //private IArdCameraService ardCameraService; @Resource private ArdChannelMapper ardChannelMapper; @Resource private IArdVtduService ardVtduService; @Resource private MediamtxConfig mediamtxConfig; @Resource private RedisCache redisCache; /** * 查询通道管理 @@ -143,102 +136,5 @@ return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; } @Scheduled(fixedDelay = 5000) public void syncVtdu() { log.debug("定时同步Vtdu任务"); List<ArdChannel> channels = this.selectArdChannelList(new ArdChannel()); if (channels == null || channels.isEmpty()) { // log.warn("没有获取到通道数据,退出同步"); return; } List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu()); Set<String> validNames = channels.stream() .map(channel -> channel.getDeviceId() + "_" + channel.getChanNo()) .collect(Collectors.toSet()); // 2. 合并操作:增、删、改 channels.forEach(channel -> { String name = channel.getDeviceId() + "_" + channel.getChanNo(); // 生成媒体表的 name String cameraId = channel.getDeviceId(); // cameraId 就是通道的 deviceId String rtspSourceUrl = getRtspSource(channel); String rtspUrl = "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name; // // 拼接 webrtcUrl String rtmpUrl = "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; // 拼接 // webrtcUrl String protocol = mediamtxConfig.isHttps() ? "https://" : "http://"; String webrtcUrl = protocol + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getWebrtcPort() + "/" + name; // 拼接 webrtcUrl // 先检查媒体表是否已有此记录 Optional<ArdVtdu> existingMedia = ardVtduList.stream() .filter(media -> media.getName().equals(name)) // 查找是否已有对应的媒体记录 .findFirst(); if (existingMedia.isPresent()) { // 如果已有,更新现有记录 ArdVtdu vtdu = existingMedia.get(); // 更新前后内容相同则不进行更新 if (!vtdu.getRtspSource().equals(rtspSourceUrl) || !vtdu.getWebrtcUrl().equals(webrtcUrl) || !vtdu.getRtspUrl().equals(rtspUrl) || !vtdu.getRtmpUrl().equals(rtmpUrl)) { vtdu.setRtspUrl(rtspUrl); vtdu.setRtmpUrl(rtmpUrl); vtdu.setWebrtcUrl(webrtcUrl); ardVtduService.updateArdVtdu(vtdu); log.info("更新媒体记录:{}", vtdu.getName()); } } else { // 如果没有,插入新的记录 ArdVtdu vtdu = new ArdVtdu(); vtdu.setName(name); vtdu.setRtspSource(rtspSourceUrl); vtdu.setCameraId(cameraId); vtdu.setRtspUrl(rtspUrl); vtdu.setRtmpUrl(rtmpUrl); vtdu.setWebrtcUrl(webrtcUrl); ardVtduService.insertArdVtdu(vtdu); // 保存到媒体表 log.info("插入新媒体记录:{}", vtdu.getName()); } }); // 3. 删除操作:删除媒体表中多余的记录 List<String> invalidNames = ardVtduList.stream() .filter(vtdu -> !validNames.contains(vtdu.getName())) .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流 .map(ArdVtdu::getName) .collect(Collectors.toList()); if (!invalidNames.isEmpty()) { // 将 List<String> 转换为 String[] String[] namesArray = invalidNames.toArray(new String[0]); ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组 log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray)); } } // 根据通道信息获取rtsp源地址 private String getRtspSource(ArdChannel channel) { String rtspSource = ""; ArdCamera ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + channel.getDeviceId()); if (ardCamera != null) { switch (ardCamera.getFactory()) { case "1": rtspSource = "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream"; break; case "2": rtspSource = "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0"; break; } } return rtspSource; } } ard-quartz/pom.xml
@@ -38,6 +38,10 @@ <groupId>com.ard</groupId> <artifactId>ard-work</artifactId> </dependency> <dependency> <groupId>com.ard</groupId> <artifactId>ard-device</artifactId> </dependency> </dependencies> ard-quartz/src/main/java/com/ard/quartz/task/DeviceTask.java
New file @@ -0,0 +1,258 @@ package com.ard.quartz.task; import com.ard.common.constant.CacheConstants; import com.ard.common.core.redis.RedisCache; import com.ard.common.utils.DateUtils; import com.ard.common.utils.file.MimeTypeUtils; import com.ard.device.camera.domain.ArdCamera; import com.ard.device.camera.service.IArdCameraService; import com.ard.device.channel.domain.ArdChannel; import com.ard.device.channel.service.IArdChannelService; import com.ard.device.component.sdk.service.CameraSDKService; import com.ard.oss.service.impl.OssServiceContext; import com.ard.vtdu.config.MediamtxConfig; import com.ard.vtdu.domain.ArdVtdu; import com.ard.vtdu.service.IArdMediaService; import com.ard.vtdu.service.IArdVtduService; import com.ard.work.domain.entity.ArdMediaPic; import com.ard.work.domain.entity.ArdMediaVideo; import com.ard.work.mapper.ArdMediaPicMapper; import com.ard.work.mapper.ArdMediaVideoMapper; import com.ard.work.util.osSelect; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import javax.annotation.Resource; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.security.cert.X509Certificate; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; /** * 定时同步设备任务 * * @author ard */ @Component("DeviceTask") @Slf4j public class DeviceTask { @Resource private RedisCache redisCache; @Resource private IArdChannelService ardChannelService; @Resource private IArdVtduService ardVtduService; @Resource private MediamtxConfig mediamtxConfig; @Resource private CameraSDKService cameraSDKService; @Resource private IArdCameraService ardCameraService; @Resource private IArdMediaService ardMediaService; /** * 定时执行登录失败相机重新登录 */ public void failedReconnect() { try { log.debug("定时执行失败相机重连任务"); // 从数据库取全部设备 ArdCamera ardCamera = new ArdCamera(); ardCamera.setUseDataScope(false); List<ArdCamera> cameraList = ardCameraService.selectArdCameraList(ardCamera); cameraList.stream() // 只处理登录失败或离线的设备 .filter(camera -> camera.getLoginId() == null || camera.getLoginId() < 0 || "0".equals(camera.getState())) .forEach(camera -> { log.info("尝试重新登录设备 {}:{}", camera.getIp(), camera.getPort()); cameraSDKService.login(camera); }); } catch (Exception ex) { log.error("定时执行失败相机重连任务异常:{}", ex.getMessage()); } } /** * 同步相机在线状态 */ public void syncCameraState() { try { log.debug("定时执行同步相机在线状态任务"); //调用查询方法 ArdCamera ardCamera = new ArdCamera(); ardCamera.setUseDataScope(false); List<ArdCamera> ardCameraList = ardCameraService.selectArdCameraList(ardCamera); ardCameraList .forEach(camera -> { boolean onLineNew = cameraSDKService.isOnLine(camera); boolean onLineOld = "1".equals(camera.getState()); if (onLineNew != onLineOld) { if (onLineNew) { camera.setState("1"); } else { camera.setState("0"); } camera.setUpdateTime(DateUtils.getNowDate()); ardCameraService.updateArdCamera(camera); } }); } catch (Exception ex) { log.error("同步相机在线状态异常:{}", ex.getMessage()); } } /** * 同步相机通道 */ public void syncChannel() { try { log.debug("定时执行同步通道任务"); ArdCamera camera = new ArdCamera(); camera.setUseDataScope(false); List<ArdCamera> ardCameraList = ardCameraService.selectArdCameraList(camera); if (!ardCameraList.isEmpty()) { ardCameraList .forEach(ardCamera -> { //SDK获取实际通道 List<ArdChannel> ardChannelListSDK = cameraSDKService.getChannels(ardCamera); //数据库获取通道 ArdChannel ardChannel = new ArdChannel(); ardChannel.setUseDataScope(false); ardChannel.setDeviceId(ardCamera.getId()); List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel); //同步通道 ardCameraService.asyncChannel(ardChannelListDb, ardChannelListSDK); }); } } catch (Exception ex) { log.error("定时执行同步通道任务异常:{}", ex.getMessage()); } } /** * 同步通道流媒体 */ public void syncVtdu() { log.debug("定时同步Vtdu任务"); ArdChannel ardChannel = new ArdChannel(); ardChannel.setUseDataScope(false); List<ArdChannel> channels = ardChannelService.selectArdChannelList(ardChannel); if (channels == null || channels.isEmpty()) { // log.warn("没有获取到通道数据,退出同步"); return; } List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu()); Set<String> validNames = channels.stream() .map(channel -> channel.getDeviceId() + "_" + channel.getChanNo()) .collect(Collectors.toSet()); // 2. 合并操作:增、删、改 channels.forEach(channel -> { String name = channel.getDeviceId() + "_" + channel.getChanNo(); // 生成媒体表的 name String cameraId = channel.getDeviceId(); // cameraId 就是通道的 deviceId String rtspSourceUrl = getRtspSource(channel); String rtspUrl = "rtsp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtspPort() + "/" + name; // // 拼接 webrtcUrl String rtmpUrl = "rtmp://" + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getRtmpPort() + "/" + name; // 拼接 // webrtcUrl String protocol = mediamtxConfig.isHttps() ? "https://" : "http://"; String webrtcUrl = protocol + mediamtxConfig.getPlayHost() + ":" + mediamtxConfig.getWebrtcPort() + "/" + name; // 拼接 webrtcUrl // 先检查媒体表是否已有此记录 Optional<ArdVtdu> existingMedia = ardVtduList.stream() .filter(media -> media.getName().equals(name)) // 查找是否已有对应的媒体记录 .findFirst(); if (existingMedia.isPresent()) { // 如果已有,更新现有记录 ArdVtdu vtdu = existingMedia.get(); // 更新前后内容相同则不进行更新 if (!vtdu.getRtspSource().equals(rtspSourceUrl) || !vtdu.getWebrtcUrl().equals(webrtcUrl) || !vtdu.getRtspUrl().equals(rtspUrl) || !vtdu.getRtmpUrl().equals(rtmpUrl)) { vtdu.setRtspUrl(rtspUrl); vtdu.setRtmpUrl(rtmpUrl); vtdu.setWebrtcUrl(webrtcUrl); ardVtduService.updateArdVtdu(vtdu); log.info("更新媒体记录:{}", vtdu.getName()); } } else { // 如果没有,插入新的记录 ArdVtdu vtdu = new ArdVtdu(); vtdu.setName(name); vtdu.setRtspSource(rtspSourceUrl); vtdu.setCameraId(cameraId); vtdu.setRtspUrl(rtspUrl); vtdu.setRtmpUrl(rtmpUrl); vtdu.setWebrtcUrl(webrtcUrl); ardVtduService.insertArdVtdu(vtdu); // 保存到媒体表 log.info("插入新媒体记录:{}", vtdu.getName()); } }); // 3. 删除操作:删除媒体表中多余的记录 List<String> invalidNames = ardVtduList.stream() .filter(vtdu -> !validNames.contains(vtdu.getName())) .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流 .map(ArdVtdu::getName) .collect(Collectors.toList()); if (!invalidNames.isEmpty()) { // 将 List<String> 转换为 String[] String[] namesArray = invalidNames.toArray(new String[0]); ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组 log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray)); } } // 根据通道信息获取rtsp源地址 private String getRtspSource(ArdChannel channel) { String rtspSource = ""; ArdCamera ardCamera = redisCache.getCacheObject(CacheConstants.CAMERA_LIST_KEY + channel.getDeviceId()); if (ardCamera != null) { switch (ardCamera.getFactory()) { case "1": rtspSource = "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream"; break; case "2": rtspSource = "rtsp://" + ardCamera.getUsername() + ":" + ardCamera.getPassword() + "@" + ardCamera.getIp() + ":" + ardCamera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0"; break; } } return rtspSource; } /** * 同步mediamtx */ public void syncMediamtx() { log.debug("定时同步MediaMTX任务"); List<String> nameList = ardMediaService.getNameList(); List<ArdVtdu> ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu()); ardVtduService.asyncMediaMTX(ardVtduList, nameList); } } ard-vtdu/src/main/java/com/ard/vtdu/service/impl/ArdVtduServiceImpl.java
@@ -38,14 +38,6 @@ mediaService.clearAll(); } @Scheduled(fixedDelay = 5000) public void syncMediamtx() { log.debug("定时同步MediaMTX任务"); List<String> nameList = mediaService.getNameList(); List<ArdVtdu> ardVtduList = selectArdVtduList(new ArdVtdu()); asyncMediaMTX(ardVtduList, nameList); } /** * 查询流媒体管理 * ard-work/src/main/java/com/ard/work/service/impl/ArdDroneInfoServiceImpl.java
@@ -362,32 +362,5 @@ } /** * 更新 localBoxInfo 的字段,如果有变化返回 true,否则返回 false */ private boolean updateChangedAttributes(ArdDroneInfo localBoxInfo, BoxInfoReceiver remoteArdDrone) { boolean changed = false; if (!Objects.equals(localBoxInfo.getBoxName(), remoteArdDrone.getBoxName())) { localBoxInfo.setBoxName(remoteArdDrone.getBoxName()); changed = true; } if (!Objects.equals(localBoxInfo.getBoxVersion(), remoteArdDrone.getBoxVersion())) { localBoxInfo.setBoxVersion(remoteArdDrone.getBoxVersion()); changed = true; } if (!Objects.equals(localBoxInfo.getLastTaskId(), remoteArdDrone.getLastTaskId())) { localBoxInfo.setLastTaskId(remoteArdDrone.getLastTaskId()); changed = true; } if (!Objects.equals(localBoxInfo.getOnLine(), remoteArdDrone.getOnLine())) { localBoxInfo.setOnLine(remoteArdDrone.getOnLine()); changed = true; } // TODO: 更新其他属性时,如果变化也设置 changed = true return changed; } }