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