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; 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.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; /** * 通道管理Service业务层处理 * * @author ard * @date 2023-08-19 */ @Slf4j @Service public class ArdChannelServiceImpl implements IArdChannelService { @Resource private ArdChannelMapper ardChannelMapper; @Resource private RedisCache redisCache; @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/10 * * * * ?") public void syncVtdu() { log.debug("定时同步Vtdu任务"); try { ArdChannel ardChannel = new ArdChannel(); ardChannel.setUseDataScope(false); List channels = this.selectArdChannelList(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() + ":" + 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 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())) .filter(vtdu -> !"publisher".equalsIgnoreCase(vtdu.getRtspSource())) // 不是机场流 .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)); } } catch (Exception e) { log.error("定时同步Vtdu任务异常:{}", e.getMessage()); } } // 根据通道信息获取rtsp源地址 private String getRtspSource(ArdChannel channel) { String rtspSource = ""; ArdCamera ardCamera = redisCache.getCacheMapValue(CacheConstants.CAMERA_LIST, 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; } }