package com.ard.device.channel.service.impl; import com.ard.common.constant.UserConstants; import com.ard.common.utils.uuid.IdUtils; 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.mapper.ArdChannelMapper; import com.ard.device.channel.service.IArdChannelService; import com.ard.vtdu.config.MediamtxConfig; import com.ard.vtdu.domain.ArdVtdu; import com.ard.vtdu.service.IArdVtduService; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.*; import java.util.stream.Collectors; /** * 通道管理Service业务层处理 * * @author ard * @date 2023-08-19 */ @Slf4j @Service public class ArdChannelServiceImpl implements IArdChannelService { @Resource private IArdCameraService ardCameraService; @Resource private ArdChannelMapper ardChannelMapper; @Resource private IArdVtduService ardVtduService; @Resource private MediamtxConfig mediamtxConfig; /** * 查询通道管理 * * @param id 通道管理主键 * @return 通道管理 */ @Override public ArdChannel selectArdChannelById(String id) { return ardChannelMapper.selectArdChannelById(id); } /** * 查询通道管理列表 * * @param ardChannel 通道管理 * @return 通道管理 */ @Override public List selectArdChannelList(ArdChannel ardChannel) { return ardChannelMapper.selectArdChannelList(ardChannel); } /** * 新增通道管理 * * @param ardChannel 通道管理 * @return 结果 */ @Override public int insertArdChannel(ArdChannel ardChannel) { ardChannel.setId(IdUtils.simpleUUID()); return ardChannelMapper.insertArdChannel(ardChannel); } /** * 修改通道管理 * * @param ardChannel 通道管理 * @return 结果 */ @Override public int updateArdChannel(ArdChannel ardChannel) { return ardChannelMapper.updateArdChannel(ardChannel); } /** * 批量删除通道管理 * * @param ids 需要删除的通道管理主键 * @return 结果 */ @Override public int deleteArdChannelByIds(String[] ids) { return ardChannelMapper.deleteArdChannelByIds(ids); } /** * 删除通道管理信息 * * @param id 通道管理主键 * @return 结果 */ @Override public int deleteArdChannelById(String id) { return ardChannelMapper.deleteArdChannelById(id); } /** * 清空通道 * * @author 刘苏义 * @date 2024/8/10 11:18 */ @Override public int clearArdChannel(){ return ardChannelMapper.clearArdChannel(); } /** * 删除通道管理信息 * * @param deviceId 所属设备ID * @return 结果 */ @Override public int deleteArdChannelByDeviceId(String deviceId) { return ardChannelMapper.deleteArdChannelByDeviceId(deviceId); } /** * 校验相机通道是否唯一 * * @param channel 通道信息 * @return 结果 */ @Override public boolean checkArdChannelUnique(ArdChannel channel) { ArdChannel info = ardChannelMapper.checkArdChannelUnique(channel); if (info != null && !Objects.equals(info.getId(), channel.getId())) { return UserConstants.NOT_UNIQUE; } return UserConstants.UNIQUE; } @Scheduled(cron = "0/5 * * * * ?") public void syncVtdu() { log.debug("定时同步Vtdu任务"); List channels = this.selectArdChannelList(new ArdChannel()); if (channels == null || channels.isEmpty()) { log.warn("没有获取到通道数据,退出同步"); return; } List ardVtduList = ardVtduService.selectArdVtduList(new ArdVtdu()); Set 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 // 先检查媒体表是否已有此记录 Optional 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 invalidNames = ardVtduList.stream() .filter(vtdu -> !validNames.contains(vtdu.getName())) .map(ArdVtdu::getName) .collect(Collectors.toList()); if (!invalidNames.isEmpty()) { // 将 List 转换为 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 =ardCameraService.selectArdCameraById(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; } }