liusuyi
2026-02-10 4ac9edd4c0030d2daafd712cd14ef9080b2f1e43
ard-device/src/main/java/com/ard/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -1,6 +1,8 @@
package com.ard.device.channel.service.impl;
import com.ard.common.constant.CacheConstants;
import com.ard.common.constant.UserConstants;
import com.ard.common.core.redis.RedisCache;
import com.ard.common.utils.uuid.IdUtils;
import com.ard.device.camera.domain.ArdCamera;
import com.ard.device.camera.service.IArdCameraService;
@@ -11,8 +13,10 @@
import com.ard.vtdu.domain.ArdVtdu;
import com.ard.vtdu.service.IArdVtduService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;
@@ -26,14 +30,16 @@
@Slf4j
@Service
public class ArdChannelServiceImpl implements IArdChannelService {
    @Resource
    private IArdCameraService ardCameraService;
    @Resource
    private ArdChannelMapper ardChannelMapper;
    @Resource
    private RedisCache redisCache;
    @Resource
    private IArdVtduService ardVtduService;
    @Resource
    private MediamtxConfig mediamtxConfig;
    /**
     * 查询通道管理
     *
@@ -105,12 +111,13 @@
     * 清空通道
     *
     * @author 刘苏义
     * @date   2024/8/10 11:18
     * @date 2024/8/10 11:18
     */
    @Override
    public int clearArdChannel(){
    public int clearArdChannel() {
        return ardChannelMapper.clearArdChannel();
    }
    /**
     * 删除通道管理信息
     *
@@ -121,6 +128,7 @@
    public int deleteArdChannelByDeviceId(String deviceId) {
        return ardChannelMapper.deleteArdChannelByDeviceId(deviceId);
    }
    /**
     * 校验相机通道是否唯一
     *
@@ -130,80 +138,96 @@
    @Override
    public boolean checkArdChannelUnique(ArdChannel channel) {
        ArdChannel info = ardChannelMapper.checkArdChannelUnique(channel);
        if (info != null && !Objects.equals(info.getId(), channel.getId()))
        {
        if (info != null && !Objects.equals(info.getId(), channel.getId())) {
            return UserConstants.NOT_UNIQUE;
        }
        return UserConstants.UNIQUE;
    }
    @Scheduled(cron = "0/5 * * * * ?")
    /**
     * 同步通道流媒体
     */
    @Scheduled(cron = "0/10 * * * * ?")
    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());
        try {
            ArdChannel ardChannel = new ArdChannel();
            ardChannel.setUseDataScope(false);
            List<ArdChannel> channels = this.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() + ":8554" + "/" + name;  // 拼接 webrtcUrl
            String rtmpUrl = "rtmp://" + mediamtxConfig.getPlayHost() + ":1935" + "/" + name;  // 拼接 webrtcUrl
            String protocol = mediamtxConfig.isHttps() ? "https://" : "http://";
            String webrtcUrl = protocol + mediamtxConfig.getPlayHost() + ":8889" + "/" + name;  // 拼接 webrtcUrl
            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();
                // 先检查媒体表是否已有此记录
                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)) {
                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.updateArdVtdu(vtdu);
                    log.info("更新媒体记录:{}", vtdu.getName());
                    ardVtduService.insertArdVtdu(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()))
                .map(ArdVtdu::getName)
                .collect(Collectors.toList());
            });
            // 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));
            if (!invalidNames.isEmpty()) {
                // 将 List<String> 转换为 String[]
                String[] namesArray = invalidNames.toArray(new String[0]);
                ardVtduService.deleteArdVtduByNames(namesArray); // 传递数组
                log.info("删除不再存在的媒体记录:{}", Arrays.toString(namesArray));
            }
        } catch (Exception e) {
            log.error("定时同步Vtdu任务异常:{}", e.getMessage());
        }
    }
@@ -211,7 +235,7 @@
    // 根据通道信息获取rtsp源地址
    private String getRtspSource(ArdChannel channel) {
        String rtspSource = "";
        ArdCamera ardCamera =ardCameraService.selectArdCameraById(channel.getDeviceId());
        ArdCamera ardCamera = redisCache.getCacheMapValue(CacheConstants.CAMERA_LIST, channel.getDeviceId());
        if (ardCamera != null) {
            switch (ardCamera.getFactory()) {
                case "1":