liusuyi
2024-07-10 016aa105789fca71e86cdbb0d26a181812f200f9
优化:流媒体同步任务
已添加1个文件
已重命名1个文件
已修改34个文件
934 ■■■■■ 文件已修改
ard-work/src/main/java/com/ruoyi/app/position/controller/ArdAppPositionController.java 118 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/app/position/service/impl/AppPositionPushService.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/controller/ArdCallSessionUserController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/dto/CallMessage.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/mapper/ArdCallSessionUserMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/service/IArdCallSessionUserService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallGroupUserServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallHistoryServiceImpl.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallSessionUserServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/Items.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/Paths.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/RtmpSession.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/RtspSession.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/Vtdu.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/domain/WebrtcSession.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/mapper/VtduMapper.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/lib/ToolKits.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/utils/websocket/service/ChatServerEndpoint.java 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/resources/mapper/call/ArdCallSessionUserMapper.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/resources/mapper/vtdu/VtduMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java 105 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ard-work/src/main/java/com/ruoyi/app/position/controller/ArdAppPositionController.java
@@ -31,19 +31,22 @@
import com.ruoyi.common.core.page.TableDataInfo;
import org.springframework.web.multipart.MultipartFile;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.*;
/**
 * app位置Controller
 *
 *
 * @author ard
 * @date 2023-07-18
 */
@Api(tags = "app位置")
@RestController
@RequestMapping("/app/position")
public class ArdAppPositionController extends BaseController
{
public class ArdAppPositionController extends BaseController {
    @Autowired
    private IArdAppPositionService ardAppPositionService;
    @Autowired
@@ -57,8 +60,7 @@
    @ApiOperation("查询app位置列表")
//    @PreAuthorize("@ss.hasPermi('app:position:list')")
    @GetMapping("/list")
    public TableDataInfo list(ArdAppPosition ardAppPosition)
    {
    public TableDataInfo list(ArdAppPosition ardAppPosition) {
        startPage();
        List<ArdAppPosition> list = ardAppPositionService.selectArdAppPositionList(ardAppPosition);
        return getDataTable(list);
@@ -70,8 +72,7 @@
    @PreAuthorize("@ss.hasPermi('app:position:export')")
    @Log(title = "app位置", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ArdAppPosition ardAppPosition)
    {
    public void export(HttpServletResponse response, ArdAppPosition ardAppPosition) {
        List<ArdAppPosition> list = ardAppPositionService.selectArdAppPositionList(ardAppPosition);
        ExcelUtil<ArdAppPosition> util = new ExcelUtil<ArdAppPosition>(ArdAppPosition.class);
        util.exportExcel(response, list, "app位置数据");
@@ -82,8 +83,7 @@
     */
    @PreAuthorize("@ss.hasPermi('app:position:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id)
    {
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(ardAppPositionService.selectArdAppPositionById(id));
    }
@@ -94,8 +94,7 @@
//    @PreAuthorize("@ss.hasPermi('app:position:add')")
    @Log(title = "app位置", businessType = BusinessType.INSERT)
    @PostMapping
    public AjaxResult add(@RequestBody ArdAppPosition ardAppPosition)
    {
    public AjaxResult add(@RequestBody ArdAppPosition ardAppPosition) {
        return AjaxResult.success(ardAppPositionService.insertArdAppPosition(ardAppPosition));
    }
@@ -105,8 +104,7 @@
    @PreAuthorize("@ss.hasPermi('app:position:edit')")
    @Log(title = "app位置", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody ArdAppPosition ardAppPosition)
    {
    public AjaxResult edit(@RequestBody ArdAppPosition ardAppPosition) {
        return toAjax(ardAppPositionService.updateArdAppPosition(ardAppPosition));
    }
@@ -115,19 +113,18 @@
     */
    @PreAuthorize("@ss.hasPermi('app:position:remove')")
    @Log(title = "app位置", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids)
    {
    @DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable String[] ids) {
        return toAjax(ardAppPositionService.deleteArdAppPositionByIds(ids));
    }
    /**
     * èŽ·å–æ‰€æœ‰ç”¨æˆ·
     */
    @ApiOperation("获取所有用户")
    @GetMapping("/getUserlist")
    public AjaxResult getUserlist(Long deptId)
    {
        SysUser user=new SysUser();
    public AjaxResult getUserlist(Long deptId) {
        SysUser user = new SysUser();
        user.setDeptId(deptId);
        List<SysUser> list = sysUserService.selectUserList(user);
        return AjaxResult.success(list);
@@ -144,57 +141,50 @@
        List<SysUser> list = sysUserService.selectAllAppUserList(user);
        return AjaxResult.success(list);
    }
    /**
     * èŽ·å–æ‰€æœ‰app用户
     */
    @ApiOperation("获取所有app用户pc")
    @GetMapping("/getAppUserForPclist")
    public AjaxResult getAppUserForPclist(Long deptId)
    {
        SysUser user=new SysUser();
    public AjaxResult getAppUserForPclist(Long deptId) {
        SysUser user = new SysUser();
        user.setDeptId(deptId);
        List<SysUser> list = sysUserService.selectAllAppUserList(user);
        List<SysUser> onLineList=new ArrayList<>();
        List<SysUser> offLineList=new ArrayList<>();
        for(SysUser sysUser:list)
        {
        List<SysUser> onLineList = new ArrayList<>();
        List<SysUser> offLineList = new ArrayList<>();
        for (SysUser sysUser : list) {
            ArdAppPosition ardAppPosition = ardAppPositionService.selectLastArdAppPositionByUserId(sysUser.getUserId());
            if(ardAppPosition!=null) {
                Map<String, Object> params =new HashMap<>();
            if (ardAppPosition != null) {
                Map<String, Object> params = new HashMap<>();
                params.put("longitude", ardAppPosition.getLongitude());
                params.put("latitude", ardAppPosition.getLatitude());
                params.put("altitude", ardAppPosition.getAltitude());
                params.put("bearing", ardAppPosition.getBearing());
                sysUser.setParams(params);
            }
            if(StringUtils.isNotNull(sysUser.getAppOnlineState()))
            {
                if(sysUser.getAppOnlineState().equals("1"))
                {
            if (StringUtils.isNotNull(sysUser.getAppOnlineState())) {
                if (sysUser.getAppOnlineState().equals("1")) {
                    onLineList.add(sysUser);
                }
                else
                {
                } else {
                    offLineList.add(sysUser);
                }
            }
            else
            {
            } else {
                offLineList.add(sysUser);
            }
        }
        Map<String,Object> onlineMap=new HashMap<>();
        onlineMap.put("children",onLineList);
        onlineMap.put("name","在线用户("+onLineList.size()+")");
        onlineMap.put("disabled",true);
        onlineMap.put("id","onLine");
        Map<String,Object> offlineMap=new HashMap<>();
        offlineMap.put("children",offLineList);
        offlineMap.put("name","离线用户("+offLineList.size()+")");
        offlineMap.put("disabled",true);
        offlineMap.put("id","offLine");
        List< Map<String,Object> > lists = new ArrayList<>();
        Map<String, Object> onlineMap = new HashMap<>();
        onlineMap.put("children", onLineList);
        onlineMap.put("name", "在线用户(" + onLineList.size() + ")");
        onlineMap.put("disabled", true);
        onlineMap.put("id", "onLine");
        Map<String, Object> offlineMap = new HashMap<>();
        offlineMap.put("children", offLineList);
        offlineMap.put("name", "离线用户(" + offLineList.size() + ")");
        offlineMap.put("disabled", true);
        offlineMap.put("id", "offLine");
        List<Map<String, Object>> lists = new ArrayList<>();
        lists.add(onlineMap);
        lists.add(offlineMap);
        return AjaxResult.success(lists);
@@ -205,24 +195,28 @@
     */
    @ApiOperation("获取用户详情")
    @GetMapping("/getUserInfo")
    public AjaxResult getUserInfo(String userId)
    {
    public AjaxResult getUserInfo(String userId) {
        SysUser sysUser = sysUserService.selectUserById(userId);
        return AjaxResult.success(sysUser);
    }
    @PostMapping("/uploadFile")
    @ApiOperation("上传文件")
    public AjaxResult uploadFile(MultipartFile file,String type)
    {
        String url = MinioUtil.putObjectAndGetUrl("app",type, file);
        return AjaxResult.success(url);
    public AjaxResult uploadFile(MultipartFile file, String type) throws MalformedURLException, UnknownHostException {
        String urlStr = MinioUtil.putObjectAndGetUrl("app", type, file);
        URL url = new URL(urlStr);
        // æ›¿æ¢ https ä¸º http,并将主机名和端口号替换为本地地址
        String serverIpAddress = InetAddress.getLocalHost().getHostAddress();
        // æž„建新的 URL å¯¹è±¡ï¼Œä½¿ç”¨ HTTPS åè®®
        URL httpsUrl = new URL("https", serverIpAddress, url.getPort(), url.getFile());
        return AjaxResult.success(httpsUrl);
    }
    @GetMapping("/getOnlinePCOrCommander")
    @ApiOperation("查询本部门在线PC端及指挥端")
    public AjaxResult getOnlinePCOrCommander() {
        String usersId = SecurityUtils.getUserId();
        Map<String,List<SysUser>> result = ardAppPositionService.getOnlinePCOrCommander(usersId);
        Map<String, List<SysUser>> result = ardAppPositionService.getOnlinePCOrCommander(usersId);
        return AjaxResult.success(result);
    }
@@ -230,10 +224,10 @@
    @ApiOperation("单兵端查看已通过审批的在线指挥端位置")
    public AjaxResult getOnlineCommanderPosition() {
        String soilderId = SecurityUtils.getUserId();
        try{
            List<Map<String,Object>> result = ardAppPositionService.getOnlineCommanderPosition(soilderId);
        try {
            List<Map<String, Object>> result = ardAppPositionService.getOnlineCommanderPosition(soilderId);
            return AjaxResult.success(result);
        }catch(Exception e){
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error();
        }
@@ -241,11 +235,11 @@
    @PostMapping("/getAPPPositionByUserIdAndTime")
    @ApiOperation("查看APP历史位置")
    public AjaxResult getAPPPositionByUserIdAndTime(@RequestBody Map<String,String> para) {
        try{
    public AjaxResult getAPPPositionByUserIdAndTime(@RequestBody Map<String, String> para) {
        try {
            List<ArdAppPosition> result = ardAppPositionService.getAPPPositionByUserIdAndTime(para);
            return AjaxResult.success(result);
        }catch(Exception e){
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error();
        }
ard-work/src/main/java/com/ruoyi/app/position/service/impl/AppPositionPushService.java
@@ -126,6 +126,10 @@
            Map<String, Object> map = JSONObject.parseObject(message, Map.class);
            if (map.size() > 0) {
                Boolean enabled = (Boolean) map.get("enabled");
                if(enabled==null)
                {
                    return;
                }
                if (enabled) {
                    //启动全局推送
                    List<ArdAppPosition> newList = new ArrayList<>(AppPositionPushService.getAppPositionList());
@@ -172,24 +176,6 @@
                    AppPositionPushService.tempUserTimerMap.remove(userId);
                    AppPositionPushService.tempDataMap.remove(userId);
                }
                //region æ—§æ–¹æ³•
//            Map<String, List<ArdAppPosition>> dataMap = new HashMap<>();
//            List<ArdAppPosition> positionList = AppPositionPush.initDataMap.get(userId);//获取当前用户的默认发送的数据map
//            if(frequency>0)
//            {
//                //接收到频率大于0,属于申请引导,获取除引导外的其他app用户的位置List
//                List<ArdAppPosition> appPositionList = positionList.stream()
//                        .filter(obj -> !obj.getUserId().equals(uId))
//                        .collect(Collectors.toList());
//                dataMap.put(userId,appPositionList);
//            }
//           else {
//                //接收到频率等于0,属于释放引导,获取到全部app用户的位置List
//                dataMap.put(userId,AppPositionPush.getAppPositionList());
//            }
//            AppPositionPush.initDataMap.putAll(dataMap);//更新初始会话默认数据map
//            AppPositionPush.startLocationPushTask(userId,session,uId, frequency);//开启新任务
                //endregion
            }
        }
        catch (Exception ex)
ard-work/src/main/java/com/ruoyi/call/controller/ArdCallSessionUserController.java
@@ -57,11 +57,12 @@
    }
    /**
     * èŽ·å–ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨è¯¦ç»†ä¿¡æ¯
     * èŽ·å–ä¼šè¯è¯¦æƒ…
     */
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") String id) {
        return success(ardCallSessionUserService.selectArdCallSessionUserById(id));
    @ApiOperation("获取会话详情")
    @GetMapping(value = "/{userId}/{sessionId}")
    public AjaxResult getInfo(@PathVariable("userId") String userId,@PathVariable("sessionId") String sessionId) {
        return success(ardCallSessionUserService.selectArdCallSessionUserBySesionId(userId,sessionId));
    }
    /**
ard-work/src/main/java/com/ruoyi/call/dto/CallMessage.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,20 @@
package com.ruoyi.call.dto;
import lombok.Data;
/**
 * @ClassName:CallMessage
 * @Description:
 * @Author:ard
 * @Date:2024å¹´07月08日13:48
 * @Version:1.0
 **/
@Data
public class CallMessage {
    String step;
    String roomId;
    String userId;
    String targetId;
    Integer mediaType;
    Integer type;
}
ard-work/src/main/java/com/ruoyi/call/mapper/ArdCallSessionUserMapper.java
@@ -19,7 +19,7 @@
     * @return ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨
     */
    public ArdCallSessionUser selectArdCallSessionUserById(String id);
    public ArdCallSessionUser  selectArdCallSessionUserBySesionId(@Param("userId") String userId,@Param("sessionId") String sessionId);
    /**
     * æŸ¥è¯¢ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨åˆ—表
     *
ard-work/src/main/java/com/ruoyi/call/service/IArdCallSessionUserService.java
@@ -18,7 +18,7 @@
     * @return ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨
     */
    public ArdCallSessionUser selectArdCallSessionUserById(String id);
    public ArdCallSessionUser selectArdCallSessionUserBySesionId(String userId,String sessionId);
    /**
     * æŸ¥è¯¢ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨åˆ—表
     *
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallGroupUserServiceImpl.java
@@ -4,6 +4,8 @@
import java.util.List;
import com.ruoyi.call.domain.ArdCallGroup;
import com.ruoyi.call.domain.ArdCallSessionUser;
import com.ruoyi.call.mapper.ArdCallSessionUserMapper;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.DateUtils;
@@ -36,6 +38,8 @@
    private ArdCallGroupUserMapper ardCallGroupUserMapper;
    @Resource
    private SysUserMapper sysUserMapper;
    @Resource
    private ArdCallSessionUserMapper ardCallSessionUserMapper;
    /**
     * æŸ¥è¯¢ç¾¤ç»„用户中间
@@ -130,6 +134,19 @@
            ardCallGroupUser.setCreateTime(DateUtils.getNowDate());
            ardCallGroupUser.setUserId(userId);
            ardCallGroupUserMapper.insertArdCallGroupUser(ardCallGroupUser);
            //邀请成员成功后创建session
            //通过群id获取群session
            String sessionId = ardCallSessionUserMapper.getGroupSessionId("1", id);
            if (StringUtils.isNotEmpty(sessionId)) {
                ArdCallSessionUser ardCallSessionUser = new ArdCallSessionUser();
                ardCallSessionUser.setId(IdUtils.simpleUUID());
                ardCallSessionUser.setType("1");
                ardCallSessionUser.setSessionId(sessionId);
                ardCallSessionUser.setUserId(userId);
                ardCallSessionUser.setTargetId(id);
                ardCallSessionUser.setCreateTime(DateUtils.getNowDate());
                ardCallSessionUserMapper.insertArdCallSessionUser(ardCallSessionUser);
            }
        });
        return userIds.length;
    }
@@ -151,7 +168,7 @@
        //获取平台所有用户
        List<SysUser> userList = sysUserMapper.selectUserList(new SysUser());
        //获取群组内用户
        ArdCallGroupUser ardCallGroupUser=new ArdCallGroupUser();
        ArdCallGroupUser ardCallGroupUser = new ArdCallGroupUser();
        ardCallGroupUser.setGroupId(groupId);
        List<ArdCallGroupUser> ardCallGroupUsers = ardCallGroupUserMapper.selectArdCallGroupUserList(ardCallGroupUser);
        // æå–groupList中的userId到一个Set中
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallHistoryServiceImpl.java
@@ -1,7 +1,10 @@
package com.ruoyi.call.service.impl;
import java.util.HashMap;
import java.util.List;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.call.domain.*;
import com.ruoyi.call.mapper.*;
import com.ruoyi.common.utils.DateUtils;
@@ -13,12 +16,17 @@
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.call.service.IArdCallHistoryService;
import javax.annotation.Resource;
import javax.websocket.Session;
import static com.ruoyi.utils.websocket.util.WebSocketUtils.ONLINE_USER_SESSIONS;
@@ -69,6 +77,8 @@
     */
    @Override
    public int insertArdCallHistory(ArdCallHistory ardCallHistory) {
        ardCallHistory.setId(IdUtils.simpleUUID());
        ardCallHistory.setCreateTime(DateUtils.getNowDate());
        ArdCallSession ardCallSession = ardCallSessionMapper.selectArdCallSessionById(ardCallHistory.getSessionId());
@@ -86,7 +96,20 @@
                ardCallUnreadMessagesMapper.updateArdCallUnreadMessages(ardCallUnreadMessages);
            }
            //websocket发送给targetId
            WebSocketUtils.sendMessage(ONLINE_USER_SESSIONS.get(ardCallHistory.getTargetId()),ardCallHistory.getContent());
            // æž„建正则表达式模式
            String regex = "^" + Pattern.quote(ardCallHistory.getTargetId()) + "_\\d+$";
            Pattern pattern = Pattern.compile(regex);
            Map<String, Object> messageMap = new HashMap<>();
            messageMap.put("type", "message");
            messageMap.put("message", JSON.toJSONString(ardCallHistory));
            ONLINE_USER_SESSIONS.entrySet().stream()
                    .filter(entry -> {
                        Matcher matcher = pattern.matcher(entry.getKey());
                        return matcher.matches();
                    })
                    .map(Map.Entry::getValue)
                    .forEach(session -> WebSocketUtils.sendMessage(session, messageMap));
        } else {
            //更新群聊用户未读消息计数
            ArdCallGroupUser ardCallGroupUser = new ArdCallGroupUser();
@@ -106,9 +129,23 @@
                        ardCallUnreadMessages.setUnreadCount(ardCallUnreadMessages.getUnreadCount() + 1);
                        ardCallUnreadMessagesMapper.updateArdCallUnreadMessages(ardCallUnreadMessages);
                    }
                    //websocket发送给targetId
                    // æž„建正则表达式模式
                    String regex = "^" + Pattern.quote(groupUser.getUserId()) + "_\\d+$";
                    Pattern pattern = Pattern.compile(regex);
                    Map<String, Object> messageMap = new HashMap<>();
                    messageMap.put("type", "message");
                    messageMap.put("message", JSON.toJSONString(ardCallHistory));
                    ONLINE_USER_SESSIONS.entrySet().stream()
                            .filter(entry ->
                            {
                                Matcher matcher = pattern.matcher(entry.getKey());
                                return matcher.matches();
                            })
                            .map(Map.Entry::getValue)
                            .forEach(session -> WebSocketUtils.sendMessage(session, messageMap));
                }
                //websocket发送给targetId
                WebSocketUtils.sendMessage(ONLINE_USER_SESSIONS.get(groupUser.getUserId()),ardCallHistory.getContent());
            });
        }
ard-work/src/main/java/com/ruoyi/call/service/impl/ArdCallSessionUserServiceImpl.java
@@ -54,6 +54,25 @@
        return ardCallSessionUserMapper.selectArdCallSessionUserById(id);
    }
    @Override
    public ArdCallSessionUser selectArdCallSessionUserBySesionId(String userId,String sessionId) {
        ArdCallSessionUser ardCallSessionUser = ardCallSessionUserMapper.selectArdCallSessionUserBySesionId(userId,sessionId);
        if(ardCallSessionUser!=null)
        {
            //获取未读数量
            ArdCallUnreadMessages ardCallUnreadMessages = ardCallUnreadMessagesMapper.getUnreadMessage(ardCallSessionUser.getSessionId(), ardCallSessionUser.getUserId());
            if (ardCallUnreadMessages != null) {
                ardCallSessionUser.setUnReadCount(ardCallUnreadMessages.getUnreadCount());
            } else {
                ardCallSessionUser.setUnReadCount(0);
            }
            //获取最后一条消息实体
            ArdCallHistory ardCallHistory = ardCallHistoryMapper.selectLastArdCallHistory(ardCallSessionUser.getSessionId());
            ardCallSessionUser.setArdCallHistory(ardCallHistory);
        }
        return ardCallSessionUser;
    }
    /**
     * æŸ¥è¯¢ä¼šè¯ç”¨æˆ·ä¸­é—´è¡¨åˆ—表
     *
ard-work/src/main/java/com/ruoyi/device/camera/service/impl/ArdCamerasServiceImpl.java
@@ -85,7 +85,8 @@
        for (ArdCameras ardCamera : ardCameras) {
            redisCache.setCacheObject(getCacheKey(ardCamera.getId()), ardCamera);
        }
        //清空流媒体
        vtduService.clearVtdu();
    }
    /**
@@ -95,7 +96,7 @@
     * @Param
     * @return
     */
    @Scheduled(cron = "0 0/10 * * * ?")
    //@Scheduled(cron = "0 0/10 * * * ?")
    public void clearRecordTemp()
    {
        log.debug("定时清理本地录像缓存文件(超过1天)");
ard-work/src/main/java/com/ruoyi/device/channel/service/IArdChannelService.java
@@ -65,4 +65,29 @@
     * @return ç»“æžœ
     */
     public int deleteArdChannelByDeviceId(String deviceId);
     /**
      * @Author åˆ˜è‹ä¹‰
      * @Description èŽ·å–2个通道列表的交集
      * @Date   2024/7/10 9:38
      * @Param
      * @return
      */
    public List<ArdChannel> sameList(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList);
    /**
     * @Author åˆ˜è‹ä¹‰
     * @Description å–2个通道列表的差集
     * @Date   2024/7/10 9:39
     * @Param
     * @return
     */
    public List<ArdChannel> diffList(List<ArdChannel> firstArrayList, List<ArdChannel> secondArrayList);
    /**
     * @Author åˆ˜è‹ä¹‰
     * @Description åŒæ­¥é€šé“信息
     * @Date 2024/7/10 13:20
     * @Param
     * @return
     */
    public void asyncChannel(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList);
}
ard-work/src/main/java/com/ruoyi/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.device.channel.service.impl;
import java.util.List;
import java.util.stream.Collectors;
import com.ruoyi.common.utils.uuid.IdUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -8,6 +9,8 @@
import com.ruoyi.device.channel.mapper.ArdChannelMapper;
import com.ruoyi.device.channel.domain.ArdChannel;
import com.ruoyi.device.channel.service.IArdChannelService;
import javax.annotation.Resource;
/**
 * é€šé“管理Service业务层处理
@@ -17,7 +20,7 @@
 */
@Service
public class ArdChannelServiceImpl implements IArdChannelService {
    @Autowired
    @Resource
    private ArdChannelMapper ardChannelMapper;
    /**
@@ -50,8 +53,8 @@
     */
    @Override
    public int insertArdChannel(ArdChannel ardChannel) {
                ardChannel.setId(IdUtils.simpleUUID());
            return ardChannelMapper.insertArdChannel(ardChannel);
        ardChannel.setId(IdUtils.simpleUUID());
        return ardChannelMapper.insertArdChannel(ardChannel);
    }
    /**
@@ -86,6 +89,7 @@
    public int deleteArdChannelById(String id) {
        return ardChannelMapper.deleteArdChannelById(id);
    }
    /**
     * åˆ é™¤é€šé“管理信息
     *
@@ -96,4 +100,39 @@
    public int deleteArdChannelByDeviceId(String deviceId) {
        return ardChannelMapper.deleteArdChannelByDeviceId(deviceId);
    }
}
    //求两个对象List的交集
    @Override
    public List<ArdChannel> sameList(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) {
        List<ArdChannel> resultList = newArrayList.stream()
                .filter(item -> oldArrayList.stream().map(e -> e.getChanNo())
                        .collect(Collectors.toList()).contains(item.getChanNo()))
                .collect(Collectors.toList());
        return resultList;
    }
    //求两个对象List的差集
    @Override
    public List<ArdChannel> diffList(List<ArdChannel> firstArrayList, List<ArdChannel> secondArrayList) {
        List<ArdChannel> resultList = firstArrayList.stream()
                .filter(item -> !secondArrayList.stream().map(e -> e.getChanNo()).collect(Collectors.toList()).contains(item.getChanNo()))
                .collect(Collectors.toList());
        return resultList;
    }
    @Override
    public void asyncChannel(List<ArdChannel> oldArrayList, List<ArdChannel> newArrayList) {
        //需要更新的数据,参数顺序注意
        sameList(oldArrayList, newArrayList).stream().forEach(ardChannel -> {
            updateArdChannel(ardChannel);
        });
        //需要删除的数据
        diffList(oldArrayList, newArrayList).stream().forEach(ardChannel -> {
            deleteArdChannelById(ardChannel.getId());
        });
        //需要新增的数据
        diffList(newArrayList, oldArrayList).stream().forEach(ardChannel -> {
            insertArdChannel(ardChannel);
        });
    }
}
ard-work/src/main/java/com/ruoyi/media/controller/MediaController.java
@@ -193,13 +193,4 @@
        return getDataTable(mediaService.getPullStreamList());
    }
    /**
     * é…ç½®æµåª’体参数
     */
    @PostMapping("/setConfig")
    @ApiOperation("配置流媒体参数")
    @ApiOperationSupport(order = 8)
    public AjaxResult setConfig(@RequestBody Config config) {
        return AjaxResult.success(mediaService.setConfig(config));
    }
}
ard-work/src/main/java/com/ruoyi/media/controller/VtduController.java
@@ -114,32 +114,7 @@
     */
    @GetMapping(value = "/{name}/noPerm")
    public AjaxResult getInfoNoPerm(@PathVariable("name") String name) {
        Vtdu vtdu = vtduService.selectVtduByName(name);
        if (vtdu != null) {
            String cameraId = name.split("_")[0];
            Integer chanNo = Integer.valueOf(name.split("_")[1]);
            CameraCmd cmd = new CameraCmd(cameraId, chanNo);
            Map<String, Object> videoCompressionCfg = cameraSdkService.getVideoCompressionCfg(cmd);
            String videoEncType = (String) videoCompressionCfg.get("videoEncType");
            if (videoEncType != null) {
                if (!videoEncType.equals("标准h264")) {
                    vtdu.setIsCode("1");
                } else {
                    vtdu.setIsCode("0");
                }
            }
            else
            {
                vtdu.setIsCode("0");
            }
            //流媒体不存在新增,存在更新
            if (!mediaService.checkNameExist(name)) {
                mediaService.addPath(name, vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
            } else {
                vtduService.updateVtdu(vtdu);
            }
        }
        return success(vtdu);
        return success(vtduService.selectVtduByName(name));
    }
    /**
     * æ–°å¢žæµåª’体管理
ard-work/src/main/java/com/ruoyi/media/domain/Items.java
@@ -23,5 +23,5 @@
    private List<Readers> readers;
    private List<String> tracks;
    private Long bytesReceived;
    private Date readyTime;
}
ard-work/src/main/java/com/ruoyi/media/domain/Paths.java
ÎļþÃû´Ó ard-work/src/main/java/com/ruoyi/media/domain/JsonsRoot.java ÐÞ¸Ä
@@ -1,6 +1,5 @@
package com.ruoyi.media.domain;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
@@ -13,7 +12,7 @@
 * @Version: 1.0
 **/
@Data
public class JsonsRoot {
public class Paths {
    private int itemCount;
ard-work/src/main/java/com/ruoyi/media/domain/RtmpSession.java
@@ -15,7 +15,6 @@
public class RtmpSession {
    private String name;
    private String id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date created;
    private String remoteAddr;
    private String state;
ard-work/src/main/java/com/ruoyi/media/domain/RtspSession.java
@@ -16,7 +16,6 @@
public class RtspSession {
    private String name;
    private String id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date created;
    private String remoteAddr;
    private String state;
ard-work/src/main/java/com/ruoyi/media/domain/Vtdu.java
@@ -57,4 +57,5 @@
     * ç›¸æœºID
     */
    String cameraId;
}
ard-work/src/main/java/com/ruoyi/media/domain/WebrtcSession.java
@@ -15,7 +15,6 @@
public class WebrtcSession {
    private String name;
    private String id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date created;
    private String remoteAddr;
    private String state;
ard-work/src/main/java/com/ruoyi/media/mapper/VtduMapper.java
@@ -1,19 +1,19 @@
package com.ruoyi.media.mapper;
import java.util.List;
import com.ruoyi.media.domain.Vtdu;
/**
 * æµåª’体管理Mapper接口
 *
 *
 * @author ard
 * @date 2023-08-29
 */
public interface VtduMapper
{
public interface VtduMapper {
    /**
     * æŸ¥è¯¢æµåª’体管理
     *
     *
     * @param name æµåª’体管理主键
     * @return æµåª’体管理
     */
@@ -21,7 +21,7 @@
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     *
     *
     * @param vtdu æµåª’体管理
     * @return æµåª’体管理集合
     */
@@ -29,7 +29,7 @@
    /**
     * æ–°å¢žæµåª’体管理
     *
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
@@ -37,7 +37,7 @@
    /**
     * ä¿®æ”¹æµåª’体管理
     *
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
@@ -50,13 +50,15 @@
     * @return ç»“æžœ
     */
    public int deleteVtduByName(String name);
    /**
     * æ‰¹é‡åˆ é™¤æµåª’体管理
     *
     *
     * @param names éœ€è¦åˆ é™¤çš„æ•°æ®ä¸»é”®é›†åˆ
     * @return ç»“æžœ
     */
    public int deleteVtduByNames(String[] names);
    /**
     * åˆ é™¤æµåª’体管理信息
     *
@@ -64,4 +66,6 @@
     * @return ç»“æžœ
     */
    public int deleteVtduByCameraId(String cameraId);
    public void clearVtdu();
}
ard-work/src/main/java/com/ruoyi/media/service/IMediaService.java
@@ -55,10 +55,4 @@
    Boolean kickWebrtcSession(String sessionId);
    /**
     * é…ç½®æµåª’体参数
     * åˆ˜è‹ä¹‰
     * 2023/10/13 15:17:57
     */
    public String setConfig(Config config);
}
ard-work/src/main/java/com/ruoyi/media/service/IVtduService.java
@@ -1,19 +1,20 @@
package com.ruoyi.media.service;
import java.util.List;
import com.ruoyi.device.channel.domain.ArdChannel;
import com.ruoyi.media.domain.Vtdu;
/**
 * æµåª’体管理Service接口
 *
 *
 * @author ard
 * @date 2023-08-29
 */
public interface IVtduService
{
public interface IVtduService {
    /**
     * æŸ¥è¯¢æµåª’体管理
     *
     *
     * @param name æµåª’体管理主键
     * @return æµåª’体管理
     */
@@ -21,7 +22,7 @@
    /**
     * æŸ¥è¯¢æµåª’体管理列表
     *
     *
     * @param vtdu æµåª’体管理
     * @return æµåª’体管理集合
     */
@@ -29,7 +30,7 @@
    /**
     * æ–°å¢žæµåª’体管理
     *
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
@@ -37,7 +38,7 @@
    /**
     * ä¿®æ”¹æµåª’体管理
     *
     *
     * @param vtdu æµåª’体管理
     * @return ç»“æžœ
     */
@@ -45,7 +46,7 @@
    /**
     * æ‰¹é‡åˆ é™¤æµåª’体管理
     *
     *
     * @param names éœ€è¦åˆ é™¤çš„æµåª’体管理主键集合
     * @return ç»“æžœ
     */
@@ -53,7 +54,7 @@
    /**
     * åˆ é™¤æµåª’体管理信息
     *
     *
     * @param name æµåª’体管理主键
     * @return ç»“æžœ
     */
@@ -66,4 +67,40 @@
     * @return ç»“æžœ
     */
    public int deleteVtduByCameraId(String cameraId);
    /**
     * @Author åˆ˜è‹ä¹‰
     * @Description æ¸…空流媒体所有数据
     * @Date   2024/7/10 13:21
     * @Param
     * @return
     */
    public void clearVtdu();
    /**
     * @return
     * @Author åˆ˜è‹ä¹‰
     * @Description èŽ·å–2个通道列表的交集
     * @Date 2024/7/10 9:38
     * @Param
     */
    public List<Vtdu> sameList(List<Vtdu> vtdus, List<String> names);
    /**
     * @return
     * @Author åˆ˜è‹ä¹‰
     * @Description å–2个通道列表的差集
     * @Date 2024/7/10 9:39
     * @Param
     */
    public List<String> diffListToDel(List<Vtdu> vtdus, List<String> names);
    public List<Vtdu> diffListToAdd(List<Vtdu> vtdus, List<String> names);
    /**
     * @return
     * @Author åˆ˜è‹ä¹‰
     * @Description åŒæ­¥æµåª’体
     * @Date 2024/7/10 13:18
     * @Param
     */
    public void asyncVtdu(List<Vtdu> vtdus, List<String> names);
}
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaServiceImpl.java
@@ -1,10 +1,8 @@
package com.ruoyi.media.service.impl;
import com.alibaba.fastjson2.JSONObject;
import com.dtflys.forest.Forest;
import com.dtflys.forest.exceptions.ForestNetworkException;
import com.dtflys.forest.exceptions.ForestRuntimeException;
import com.dtflys.forest.http.ForestRequest;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.media.domain.*;
import com.ruoyi.media.service.IMediaService;
@@ -17,9 +15,7 @@
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.xml.soap.SOAPEnvelope;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -34,22 +30,14 @@
@Service
@Slf4j(topic = "vtdu")
@Order(2)
public class MediaServiceImpl implements IMediaService, ApplicationRunner {
    public static List<String> mediaNameList = new ArrayList<>();
public class MediaServiceImpl implements IMediaService {
    @Resource
    MediaClient mediaClient;
    @Value("${mediamtx.host}")
    String mediamtxHost;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        mediaNameList = getNameList();
        if (mediaNameList.size() > 0) {
            removePath(mediaNameList.toArray(new String[0]));
            mediaNameList.clear();
        }
    }
    /**
     * æ·»åŠ æµåª’ä½“
@@ -90,7 +78,8 @@
            if (!checkNameExist(name)) {
                mediaClient.addPath(name, conf);
                mediaNameList.add(name);
            } else {
                mediaClient.editPath(name, conf);
            }
            map.put("rtspUrl", rtspUrl);
@@ -188,7 +177,6 @@
        try {
            if (checkNameExist(name)) {
                mediaClient.removePath(name);
                mediaNameList.remove(name);
            }
        } catch (ForestRuntimeException ex) {
            log.error("移除流媒体异常:" + ex.getMessage());
@@ -197,9 +185,8 @@
    @Override
    public List<StreamInfo> paths() {
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        List<StreamInfo> pathInfoList = new ArrayList<>();
        for (Items item : items) {
            StreamInfo info = new StreamInfo();
@@ -261,9 +248,8 @@
    @Override
    public List<StreamInfo> getPushStreamList() {
        List<StreamInfo> PushStreamInfoList = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        for (Items item : items) {
            StreamInfo info = new StreamInfo();
            //ID
@@ -289,6 +275,7 @@
                long bytesReceived = item.getBytesReceived();
                String formatReceivedSize = ArdTool.formatFileSize(bytesReceived);
                info.setUpTraffic(formatReceivedSize);
                info.setBeginTime(item.getReadyTime());
            } else {
                RtspSession rtspSession = getRtspSessionById(source.getId());
                //会话ID
@@ -336,9 +323,8 @@
    @Override
    public List<StreamInfo> getPullStreamList() {
        List<StreamInfo> PullStreamInfoList = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        for (Items item : items) {
            List<Readers> readers = item.getReaders();
            for (Readers reader : readers) {
@@ -375,6 +361,7 @@
                        PullStreamInfoList.add(info);
                        break;
                    case "webRTCSession":
                    case "webrtcSession":
                        info.setSessionType("webrtc");
                        //webrtc播放地址
                        url = "http://" + mediamtxHost + ":8889/" + name;
@@ -478,41 +465,32 @@
     */
    @Override
    public List<String> getNameList() {
        List<String> nameList = new ArrayList<>();
        try {
            String paths = mediaClient.paths();
            JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
            List<Items> items = jsonsRoot.getItems();
            Paths paths = mediaClient.paths();
            List<Items> items = paths.getItems();
            for (Items item : items) {
                mediaNameList.add(item.getName());
                nameList.add(item.getName());
            }
        } catch (ForestNetworkException ex) {
            log.error("获取流媒体name列表异常:" + ex.getMessage());
        } catch (ForestRuntimeException ex) {
        } catch (Exception ex) {
            log.error("获取流媒体name列表异常:" + ex.getMessage());
        }
        return mediaNameList;
        return nameList;
    }
    /**
     * æ£€æŸ¥åç§°æ˜¯å¦å­˜åœ¨
     * æ£€æŸ¥name是否存在
     * åˆ˜è‹ä¹‰
     * 2023/10/19 15:18:45
     */
    @Override
    public boolean checkNameExist(String name) {
        boolean result = false;
        if (mediaNameList.contains(name)) {
        List<String> nameList = getNameList();
        if (nameList.contains(name)) {
            result = true;
        }
        return result;
    }
    /**
     * é…ç½®æµåª’体参数
     */
    @Override
    public String setConfig(Config config) {
        return mediaClient.setConfig(config);
    }
ard-work/src/main/java/com/ruoyi/media/service/impl/MediaV2ServiceImpl.java
@@ -4,7 +4,6 @@
import com.dtflys.forest.exceptions.ForestNetworkException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.media.domain.*;
import com.ruoyi.media.service.IMediaService;
import com.ruoyi.media.service.IMediaV2Service;
import com.ruoyi.utils.forest.MediaClient;
import com.ruoyi.utils.tools.ArdTool;
@@ -73,9 +72,8 @@
        conf.setSourceProtocol("tcp");
        List<String> nameList = new ArrayList<>();
        String paths = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        for (Items item : items) {
            nameList.add(item.getName());
        }
@@ -167,9 +165,8 @@
    @Override
    public List<StreamInfo> paths() {
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        List<StreamInfo> pathInfoList = new ArrayList<>();
        for (Items item : items) {
            StreamInfo info = new StreamInfo();
@@ -232,9 +229,8 @@
    @Override
    public List<StreamInfo> getPushStreamList() {
        List<StreamInfo> PushStreamInfoList = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        for (Items item : items) {
            StreamInfo info = new StreamInfo();
            //ID
@@ -306,9 +302,8 @@
    @Override
    public List<StreamInfo> getPullStreamList() {
        List<StreamInfo> PullStreamInfoList = new ArrayList<>();
        String list = mediaClient.paths();
        JsonsRoot jsonsRoot = JSONObject.parseObject(list, JsonsRoot.class);
        List<Items> items = jsonsRoot.getItems();
        Paths paths = mediaClient.paths();
        List<Items> items = paths.getItems();
        for (Items item : items) {
            List<Readers> readers = item.getReaders();
            for (Readers reader : readers) {
@@ -451,9 +446,8 @@
    public List<String> getNameList() {
        List<String> nameList = new ArrayList<>();
        try {
            String paths = mediaClient.paths();
            JsonsRoot jsonsRoot = JSONObject.parseObject(paths, JsonsRoot.class);
            List<Items> items = jsonsRoot.getItems();
            Paths paths = mediaClient.paths();
            List<Items> items = paths.getItems();
            for (Items item : items) {
                nameList.add(item.getName());
            }
ard-work/src/main/java/com/ruoyi/media/service/impl/VtduServiceImpl.java
@@ -3,8 +3,10 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.device.channel.domain.ArdChannel;
import com.ruoyi.media.service.IMediaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -141,4 +143,69 @@
        }
        return vtduMapper.deleteVtduByCameraId(cameraId);
    }
    /**
     * @return
     * @Author åˆ˜è‹ä¹‰
     * @Description æ¸…除所有流媒体数据
     * @Date 2024/7/10 13:31
     * @Param
     */
    public void clearVtdu() {
        vtduMapper.clearVtdu();
    }
    //需要更新的(流媒体和vtdu相同)
    @Override
    public List<Vtdu> sameList(List<Vtdu> vtdus, List<String> names) {
        return vtdus.stream().filter(vtdu -> names.contains(vtdu.getName())).collect(Collectors.toList());
    }
    //需要删除的(流媒体中多的)
    @Override
    public List<String> diffListToDel(List<Vtdu> vtdus, List<String> names) {
        if (vtdus.size() >= names.size()) {
            List<String> nameList = vtdus.stream().map(Vtdu::getName)
                    .filter(item -> !names.contains(item))
                    .collect(Collectors.toList());
            return nameList;
        } else {
            List<String> nameList = names.stream().filter(item -> !vtdus.stream().map(Vtdu::getName).collect(Collectors.toList()).contains(item))
                    .collect(Collectors.toList());
            return nameList;
        }
    }
    //需要新增的(流媒体中少的)
    @Override
    public List<Vtdu> diffListToAdd(List<Vtdu> vtdus, List<String> names) {
        return vtdus.stream().filter(vtdu -> !names.contains(vtdu.getName())).collect(Collectors.toList());
    }
    /**
     * @Author åˆ˜è‹ä¹‰
     * @Description  åŒæ­¥æœ¬åœ°vtdu库和流媒体中的数据
     * @Date   2024/7/10 15:26
     * @Param  vtdus vtdu库的集合
     * @Param  names æµåª’体的name集合
     * @return
     */
    @Override
    public void asyncVtdu(List<Vtdu> vtdus, List<String> names) {
        //需要更新的数据,参数顺序注意
        sameList(vtdus, names).stream().forEach(vtdu -> {
            mediaService.editPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
        });
        //需要删除的数据
        diffListToDel(vtdus, names).stream().forEach(name -> {
            mediaService.removePath(name);
        });
        //需要新增的数据
        diffListToAdd(vtdus, names).stream().forEach(vtdu -> {
            mediaService.addPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
        });
    }
}
ard-work/src/main/java/com/ruoyi/utils/forest/MediaClient.java
@@ -4,6 +4,9 @@
import com.ruoyi.media.domain.Conf;
import com.ruoyi.media.domain.Config;
import com.ruoyi.media.domain.Items;
import com.ruoyi.media.domain.Paths;
import java.nio.file.Path;
/**
 * @Description: mediamtx流媒体客户端
@@ -42,7 +45,7 @@
     * æŸ¥è¯¢æ‰€æœ‰è·¯å¾„
     */
    @Get("/paths/list")
    public String paths();
    public Paths paths();
    /**
     * æŸ¥è¯¢æ‰€æœ‰rtsp会话
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/lib/ToolKits.java
@@ -488,7 +488,7 @@
        int nBufferLen = 2*1024*1024;
        byte[] strBuffer = new byte[nBufferLen];
        if(netsdkapi.CLIENT_GetNewDevConfig( hLoginHandle, strCmd , nChn, strBuffer, nBufferLen,error,3000)) {
        if(netsdkapi.CLIENT_GetNewDevConfig( hLoginHandle, strCmd , nChn, strBuffer, nBufferLen,error,6000)) {
            cmdObject.write();
            if (configapi.CLIENT_ParseData(strCmd, strBuffer, cmdObject.getPointer(),
                    cmdObject.size(), null)) {
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/module/ConfigModule.java
@@ -81,7 +81,20 @@
        return result;
    }
    public static String getChannelName(NetSDKLib.LLong hLoginHandle,Integer channel) {
        String channelName = "";
        NetSDKLib.AV_CFG_ChannelName channelTitleName = new NetSDKLib.AV_CFG_ChannelName();
        if (ToolKits.GetDevConfig(hLoginHandle, channel, NetSDKLib.CFG_CMD_CHANNELTITLE, channelTitleName)) {
            try {
                channelName = new String(channelTitleName.szName, "GBK");
            } catch (Exception e) {
                System.err.println("getChannelName Failed!");
            }
        } else {
            System.err.println("Get Channel Name Failed." + ToolKits.getErrorCodePrint());
        }
        return channelName;
    }
    public static boolean GetDevConfig(NetSDKLib.LLong hLoginHandle, int nChn, String strCmd, Structure cmdObject) {
        boolean result = true;
        IntByReference error = new IntByReference(0);
@@ -128,6 +141,7 @@
                stOut.read();
                ToolKits.GetPointerDataToStructArr(stOut.pCameraStateInfo, arrCameraStatus);  // å°†Pointer拷贝到数组内存
                final String[] connectionState = {"未知", "正在连接", "已连接", "未连接", "通道未配置,无信息", "通道有配置,但被禁用"};
               log.debug(connectionState[arrCameraStatus[chanNo - 1].emConnectionState]);
                if (connectionState[arrCameraStatus[chanNo - 1].emConnectionState].equals("已连接")) {
                    log.debug("通道" + arrCameraStatus[chanNo - 1].nChannel + connectionState[arrCameraStatus[chanNo - 1].emConnectionState]);
                    bRet = true;
ard-work/src/main/java/com/ruoyi/utils/sdk/dhsdk/service/impl/DahuaSDK.java
@@ -112,9 +112,7 @@
                log.error("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint());
                return AjaxResult.warn(ErrorCode.getErrorCode(LoginModule.netsdk.CLIENT_GetLastError()));
            }
//            if (GlobalVariable.loginMap.containsKey(camera.getId())) {
//                GlobalVariable.loginMap.remove(camera.getId());
//            }
            camera.setState("1");
            camera.setChanNum(m_stDeviceInfo.byChanNum);
            camera.setStartDChan(1);
@@ -123,7 +121,12 @@
            //获取最新通道
            List<ArdChannel> ardChannelList = getChannels(camera);
            if (ardChannelList.size() > 0) {
                ardChannelService.deleteArdChannelByDeviceId(camera.getId());
                ardChannelList.stream().forEach(channel -> {
                    ardChannelService.insertArdChannel(channel);
                });
                camera.setChanNum(ardChannelList.size());
                camera.setChannelList(ardChannelList);
                ardCamerasService.updateArdCameras(camera);
                //配置到流媒体
                addVtdu(camera);
@@ -154,9 +157,6 @@
                log.error("设备[" + camera.getIp() + ":" + camera.getPort() + "]登录失败:" + getErrorCodePrint());
                return AjaxResult.warn(getErrorCodePrint());
            }
//            if (GlobalVariable.loginMap.containsKey(camera.getId())) {
//                GlobalVariable.loginMap.remove(camera.getId());
//            }
            camera.setState("1");
            camera.setChanNum(m_stDeviceInfo.byChanNum);
            camera.setStartDChan(1);
@@ -167,7 +167,12 @@
            //获取最新通道
            List<ArdChannel> ardChannelList = getChannels(camera);
            if (ardChannelList.size() > 0) {
                ardChannelService.deleteArdChannelByDeviceId(camera.getId());
                ardChannelList.stream().forEach(channel -> {
                    ardChannelService.insertArdChannel(channel);
                });
                camera.setChanNum(ardChannelList.size());
                camera.setChannelList(ardChannelList);
                ardCamerasService.updateArdCameras(camera);
                //配置到流媒体
                addVtdu(camera);
@@ -183,17 +188,17 @@
    //添加到流媒体
    private void addVtdu(ArdCameras camera) {
        for (int i = 1; i < camera.getChanNum() + 1; i++) {
            String name = camera.getId() + "_" + i;
            String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/cam/realmonitor?channel=" + i + "&subtype=0";
            Vtdu vtdu = vtduService.selectVtduByName(name);
            if (vtdu != null) {
        camera.getChannelList().stream().forEach(channel -> {
            String name = camera.getId() + "_" + channel.getChanNo();
            String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/cam/realmonitor?channel=" + channel.getChanNo() + "&subtype=0";
             //删除流媒体
            if (vtduService.selectVtduByName(name) != null) {
                vtduService.deleteVtduByName(name);
            }
            //添加到流媒体
            CameraCmd cmd = new CameraCmd(camera.getId(), i);
            CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo());
            Map<String, Object> videoCompressionCfg = getVideoCompressionCfg(cmd);
            vtdu = new Vtdu();
            Vtdu vtdu = new Vtdu();
            if (videoCompressionCfg.get("videoEncType") != null) {
                if (videoCompressionCfg.get("videoEncType").equals("标准h264")) {
                    vtdu.setIsCode("0");//默认不转码
@@ -204,11 +209,11 @@
                vtdu.setIsCode("0");//默认不转码
            }
            vtdu.setRtspSource(rtspSource);
            vtdu.setName(camera.getId() + "_" + i);
            vtdu.setName(name);
            vtdu.setMode("1");//默认CPU软解码
            vtdu.setCameraId(camera.getId());
            vtduService.insertVtdu(vtdu);
        }
        });
    }
    //创建引导队列
@@ -226,23 +231,12 @@
    //获取通道
    public List<ArdChannel> getChannels(ArdCameras camera) {
        ardChannelService.deleteArdChannelByDeviceId(camera.getId());
        LLong loginId = new LLong(camera.getLoginId());
        List<ArdChannel> ardChannelList = new ArrayList<>();
        for (int i = 1; i < camera.getChanNum() + 1; i++) {
            ArdChannel channel = new ArdChannel();
            NetSDKLib.AV_CFG_ChannelName av_cfg_channelName = new NetSDKLib.AV_CFG_ChannelName();
            boolean b = ConfigModule.GetNewDevConfig(loginId, i - 1, CFG_CMD_CHANNELTITLE, av_cfg_channelName);
            if (!b) {
                log.error("获取配置失败,请稍后重试" + getErrorCodePrint());
                // return AjaxResult.warn(ErrorCode.getErrorCode(LoginModule.netsdk.CLIENT_GetLastError()));
            }
            String chanName = "";
            try {
                chanName = new String(av_cfg_channelName.szName, "GBK").trim();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            String chanName = ConfigModule.getChannelName(loginId, i - 1).trim();
            log.debug("获取通道名称:" + chanName);
            channel.setName(chanName.equals("") ? "通道" + i : chanName);
            channel.setDeviceId(camera.getId());
            channel.setChanNo(i);
@@ -253,7 +247,6 @@
                }
            }
            ardChannelList.add(channel);
            ardChannelService.insertArdChannel(channel);
        }
        return ardChannelList;
    }
@@ -411,9 +404,9 @@
        float t = (float) dh_ptz_location_info.nPTZTilt / 10 * -1;
        String nPTZTilt = df.format(t < 0 ? t + 360 : t);
        String nPTZZoom = df.format((float) dh_ptz_location_info.nPTZZoom);
        ptzMap.put("p" , nPTZPan);
        ptzMap.put("t" , nPTZTilt);
        ptzMap.put("z" , nPTZZoom);
        ptzMap.put("p", nPTZPan);
        ptzMap.put("t", nPTZTilt);
        ptzMap.put("z", nPTZZoom);
        return AjaxResult.success(ptzMap);
    }
@@ -591,7 +584,7 @@
            //    return false;
            //}
            log.debug("本地录像开始");
            return AjaxResult.success("本地录像开始" , lRealHandle);
            return AjaxResult.success("本地录像开始", lRealHandle);
        } catch (Exception ex) {
            log.error("本地录像开始异常" + ex.getMessage());
            return AjaxResult.error("本地录像开始异常" + ex.getMessage());
@@ -796,7 +789,7 @@
                log.error("设置ptz失败:" + getErrorCodePrint());
                return AjaxResult.warn("设置ptz失败:" + getErrorCodePrint());
            }
            return AjaxResult.success("引导目标位置成功",correctPitch);
            return AjaxResult.success("引导目标位置成功", correctPitch);
        } catch (Exception ex) {
            log.error("引导目标位置异常:" + ex.getMessage());
            return AjaxResult.error("引导目标位置异常:" + ex.getMessage());
@@ -1110,10 +1103,10 @@
                int nHeight = cfg_encode_info.stuMainStream[0].stuVideoFormat.nHeight;
                String resolution = nWidth + "*" + nHeight;
                float nFrameRate = cfg_encode_info.stuMainStream[0].stuVideoFormat.nFrameRate;
                map.put("resolution" , resolution);//分辨率
                map.put("videoBitrate" , String.valueOf(nBitRate));//比特率
                map.put("videoEncType" , videoEncType);//编码
                map.put("nFrameRate" , String.valueOf(nFrameRate));//帧率
                map.put("resolution", resolution);//分辨率
                map.put("videoBitrate", String.valueOf(nBitRate));//比特率
                map.put("videoEncType", videoEncType);//编码
                map.put("nFrameRate", String.valueOf(nFrameRate));//帧率
            }
        } catch (Exception ex) {
            log.error("取码流压缩参数异常:" + ex.getMessage());
@@ -1140,8 +1133,8 @@
            float nAngelH = (float) dh_out_ptz_view_range_status.nAngelH / 10;
            float nAngelV = (float) dh_out_ptz_view_range_status.nAngelV / 10;
            Map<String, Object> map = getPtz(cmd);//获取ptz
            map.put("fHorFieldAngle" , nAngelH);// æ°´å¹³è§†åœºè§’
            map.put("fVerFieldAngle" , nAngelV);// åž‚直视场角
            map.put("fHorFieldAngle", nAngelH);// æ°´å¹³è§†åœºè§’
            map.put("fVerFieldAngle", nAngelV);// åž‚直视场角
            return AjaxResult.success(map);
        } catch (Exception ex) {
            log.error("获取云台可视域异常" + ex.getMessage());
ard-work/src/main/java/com/ruoyi/utils/sdk/hiksdk/service/impl/HikvisionSDK.java
@@ -144,10 +144,6 @@
                    log.debug("Set fExceptionCallBack function successfully!");
                }
            }
//            if (GlobalVariable.loginMap.containsKey(camera.getId())) {
//                GlobalVariable.loginMap.remove(camera.getId());
//            }
            GlobalVariable.loginMap.put(camera.getId(), lUserID);
            GlobalVariable.loginCameraMap.put(lUserID, camera);
            camera.setLoginId(lUserID);
@@ -163,6 +159,10 @@
            //获取最新通道
            List<ArdChannel> cameraChannelList = getChannels(camera);
            if (cameraChannelList.size() > 0) {
                ardChannelService.deleteArdChannelByDeviceId(camera.getId());
                cameraChannelList.stream().forEach(channel -> {
                    ardChannelService.insertArdChannel(channel);
                });
                camera.setChannelList(cameraChannelList);
                camera.setChanNum(cameraChannelList.size());
                ardCamerasService.updateArdCameras(camera);
@@ -251,9 +251,7 @@
                    }
                }
            }
//            if (GlobalVariable.loginMap.containsKey(camera.getId())) {
//                GlobalVariable.loginMap.remove(camera.getId());
//            }
            GlobalVariable.loginMap.put(camera.getId(), lUserID);
            GlobalVariable.loginCameraMap.put(lUserID, camera);
            camera.setLoginId(lUserID);
@@ -269,6 +267,10 @@
            //获取最新通道
            List<ArdChannel> cameraChannelList = getChannels(camera);
            if (cameraChannelList.size() > 0) {
                ardChannelService.deleteArdChannelByDeviceId(camera.getId());
                cameraChannelList.stream().forEach(channel -> {
                    ardChannelService.insertArdChannel(channel);
                });
                camera.setChannelList(cameraChannelList);
                camera.setChanNum(cameraChannelList.size());
                ardCamerasService.updateArdCameras(camera);
@@ -300,17 +302,17 @@
    //添加到流媒体
    private void addVtdu(ArdCameras camera) {
        try {
            for (ArdChannel channel : camera.getChannelList()) {
            camera.getChannelList().stream().forEach(channel->{
                String name = camera.getId() + "_" + channel.getChanNo();
                String rtspSource = "rtsp://" + camera.getUsername() + ":" + camera.getPassword() + "@" + camera.getIp() + ":" + camera.getRtspPort() + "/h264/ch" + channel.getChanNo() + "/main/av_stream";
                Vtdu vtdu = vtduService.selectVtduByName(name);
                if (vtdu != null) {
                //删除流媒体
                if (vtduService.selectVtduByName(name) != null) {
                    vtduService.deleteVtduByName(name);
                }
                //添加到流媒体
                vtdu = new Vtdu();
                Vtdu vtdu = new Vtdu();
                vtdu.setRtspSource(rtspSource);
                vtdu.setName(camera.getId() + "_" + channel.getChanNo());
                vtdu.setName(name);
                CameraCmd cmd = new CameraCmd(camera.getId(), channel.getChanNo());
                Map<String, Object> videoCompressionCfg = getVideoCompressionCfg(cmd);
                if (videoCompressionCfg.get("videoEncType").equals("标准h264")) {
@@ -321,7 +323,7 @@
                vtdu.setMode("1");//默认CPU软解码
                vtdu.setCameraId(camera.getId());
                vtduService.insertVtdu(vtdu);
            }
            });
        } catch (Exception ex) {
            log.error("通道添加到流媒体异常:" + ex.getMessage());
        }
@@ -1849,8 +1851,6 @@
        //获取通道
        List<ArdChannel> channelList = new ArrayList<>();
        try {
            //删除管理通道
            ardChannelService.deleteArdChannelByDeviceId(camera.getId());
            IntByReference ibrBytesReturned = new IntByReference(0);//获取IP接入配置参数
            HCNetSDK.NET_DVR_IPPARACFG_V40 m_strIpparaCfg = new HCNetSDK.NET_DVR_IPPARACFG_V40();
            m_strIpparaCfg.write();
@@ -1891,7 +1891,6 @@
                    }
                    channelList.add(channel);
                }
                ardChannelService.insertArdChannel(channel);
            }
        } catch (Exception ex) {
            log.error("获取IP通道异常:" + ex.getMessage());
ard-work/src/main/java/com/ruoyi/utils/websocket/service/ChatServerEndpoint.java
@@ -1,6 +1,8 @@
package com.ruoyi.utils.websocket.service;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.app.position.service.impl.AppPositionPushService;
import com.ruoyi.call.dto.CallMessage;
import com.ruoyi.utils.websocket.util.WebSocketUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@@ -9,6 +11,11 @@
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.ruoyi.utils.websocket.util.WebSocketUtils.ONLINE_USER_SESSIONS;
/**
 * @ClassName ChatServerEndpoint
@@ -33,11 +40,27 @@
    @OnMessage
    public void onMessage(@PathParam("userId") String userId, String message) {
        log.info("收到消息:" + message);
        Session session = WebSocketUtils.ONLINE_USER_SESSIONS.get(userId);
        WebSocketUtils.sendMessage(session, message);
        //sendMessageAll("用户[" + userid + "] : " + message);
//        Session session = WebSocketUtils.ONLINE_USER_SESSIONS.get(userId);
//        WebSocketUtils.sendMessage(session, message);
        Map<String, Object> messageMap = JSONObject.parseObject(message, Map.class);
        if (((String) messageMap.get("type")).equals("callMessage")) {
            String msg = (String) messageMap.get("message");
            CallMessage callMessage = JSONObject.parseObject(msg, CallMessage.class);
            if (callMessage != null && callMessage.getType().equals(0)) {
                String regex = "^" + Pattern.quote(callMessage.getTargetId()) + "_\\d+$";
                Pattern pattern = Pattern.compile(regex);
                ONLINE_USER_SESSIONS.entrySet().stream()
                        .filter(entry -> {
                            Matcher matcher = pattern.matcher(entry.getKey());
                            return matcher.matches();
                        })
                        .map(Map.Entry::getValue)
                        .forEach(session -> WebSocketUtils.sendMessage(session, message));
            }
        }
        // æ ¹æ®ç”¨æˆ·æ–°çš„频率重新调整定时任务
        AppPositionPushService.messageHandler(userId,message);
        AppPositionPushService.messageHandler(userId, message);
    }
    @OnClose
ard-work/src/main/resources/mapper/call/ArdCallSessionUserMapper.xml
@@ -27,11 +27,14 @@
        </where>
    </select>
    <select id="selectArdCallSessionUserBySesionId" parameterType="String" resultMap="ArdCallSessionUserResult">
        <include refid="selectArdCallSessionUserVo"/>
        where session_id = #{sessionId} and user_id = #{userId}
    </select>
    <select id="selectArdCallSessionUserById" parameterType="String" resultMap="ArdCallSessionUserResult">
        <include refid="selectArdCallSessionUserVo"/>
        where id = #{id}
    </select>
    <insert id="insertArdCallSessionUser" parameterType="ArdCallSessionUser">
        insert into ard_call_session_user
        <trim prefix="(" suffix=")" suffixOverrides=",">
ard-work/src/main/resources/mapper/vtdu/VtduMapper.xml
@@ -118,4 +118,7 @@
        from vtdu
        where camera_id = #{cameraId}
    </delete>
    <delete id="clearVtdu">
        delete from vtdu
    </delete>
</mapper>
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/PushTask.java
@@ -17,6 +17,7 @@
import javax.annotation.Resource;
import java.util.*;
import static com.ruoyi.utils.websocket.util.WebSocketUtils.ONLINE_USER_SESSIONS;
/**
@@ -36,6 +37,7 @@
    ICameraSdkService cameraSdkService;
    @Resource
    IGlobalAlarmService globalAlarmService;
    /**
     * @描述 å®šæ—¶æŽ¨é€æ‰€æœ‰æŠ¥è­¦çš„点位数量
     * @参数 []
@@ -66,62 +68,61 @@
     */
    public void ptzPush() {
        try {
            List<Map<String, Object>> list = new ArrayList<>();
            List<Object> Objects = redisCache.getListKey(CacheConstants.CAMERA_LIST_KEY);
            if (Objects.size() > 0) {
                for (Object obj : Objects) {
                    ArdCameras camera = (ArdCameras) obj;
                    if (!GlobalVariable.loginMap.containsKey(camera.getId()))//只推送首次登录成功的相机
                    {
                        continue;
                    }
                    if(!"1".equals(camera.getGdtype()))
                    {
                        continue;
                    }
                    CameraCmd cmd = new CameraCmd();
                    cmd.setCameraId(camera.getId());
                    cmd.setChanNo(1);
                    cmd.setOperator(camera.getOperatorId());
                    //推送在线的相机
                    boolean onLine = cameraSdkService.isOnLine(cmd);
                    if(!onLine)
                    {
                        continue;
                    }
                    AjaxResult ajaxResult = cameraSdkService.getGisInfo(cmd);
                    Map<String, Object> ptz = (Map<String, Object>)ajaxResult.get("data");
                    if (StringUtils.isNull(ptz)) {
                        continue;
                    }
                    SysUser sysUser = redisCache.getCacheObject(CacheConstants.USER_LIST_KEY + camera.getOperatorId());
                    if (StringUtils.isNotNull(sysUser)) {
                        cmd.setOperatorZh(sysUser.getNickName());
                    } else {
                        cmd.setOperatorZh(cmd.getOperator());
                    }
            if (ONLINE_USER_SESSIONS.size() > 0) {
                List<Map<String, Object>> list = new ArrayList<>();
                List<Object> Objects = redisCache.getListKey(CacheConstants.CAMERA_LIST_KEY);
                if (Objects.size() > 0) {
                    for (Object obj : Objects) {
                        ArdCameras camera = (ArdCameras) obj;
                        if (!GlobalVariable.loginMap.containsKey(camera.getId()))//只推送首次登录成功的相机
                        {
                            continue;
                        }
                        if (!"1".equals(camera.getGdtype())) {
                            continue;
                        }
                        CameraCmd cmd = new CameraCmd();
                        cmd.setCameraId(camera.getId());
                        cmd.setChanNo(1);
                        cmd.setOperator(camera.getOperatorId());
                        //推送在线的相机
                        boolean onLine = cameraSdkService.isOnLine(cmd);
                        if (!onLine) {
                            continue;
                        }
                        AjaxResult ajaxResult = cameraSdkService.getGisInfo(cmd);
                        Map<String, Object> ptz = (Map<String, Object>) ajaxResult.get("data");
                        if (StringUtils.isNull(ptz)) {
                            continue;
                        }
                        SysUser sysUser = redisCache.getCacheObject(CacheConstants.USER_LIST_KEY + camera.getOperatorId());
                        if (StringUtils.isNotNull(sysUser)) {
                            cmd.setOperatorZh(sysUser.getNickName());
                        } else {
                            cmd.setOperatorZh(cmd.getOperator());
                        }
                    //获取时间差
                    long secDatePoor = 0;
                    if (StringUtils.isNotNull(camera.getOperatorExpired())) {
                        secDatePoor = DateUtils.getSecDatePoor(camera.getOperatorExpired(), new Date());
                        if (secDatePoor < 0) {
                            secDatePoor = 0;
                        //获取时间差
                        long secDatePoor = 0;
                        if (StringUtils.isNotNull(camera.getOperatorExpired())) {
                            secDatePoor = DateUtils.getSecDatePoor(camera.getOperatorExpired(), new Date());
                            if (secDatePoor < 0) {
                                secDatePoor = 0;
                            }
                        }
                        if (ptz.size() > 0) {
                            ptz.put("cameraId", cmd.getCameraId());
                            ptz.put("usernameZh", cmd.getOperatorZh());
                            ptz.put("operatorId", cmd.getOperator());//上锁用户id
                            ptz.put("expirationRemainingSecond", secDatePoor);
                            ptz.put("longitude", camera.getLongitude());
                            ptz.put("latitude", camera.getLatitude());
                            ptz.put("altitude", camera.getAltitude());
                            list.add(ptz);
                        }
                    }
                    if (ptz.size() > 0) {
                        ptz.put("cameraId", cmd.getCameraId());
                        ptz.put("usernameZh", cmd.getOperatorZh());
                        ptz.put("operatorId", cmd.getOperator());//上锁用户id
                        ptz.put("expirationRemainingSecond", secDatePoor);
                        ptz.put("longitude",camera.getLongitude());
                        ptz.put("latitude",camera.getLatitude());
                        ptz.put("altitude",camera.getAltitude());
                        list.add(ptz);
                    }
                }
                if (ONLINE_USER_SESSIONS.size() > 0) {
                    Map<String, Object> sendMap = new HashMap<>();
                    sendMap.put("10000", list);
                    WebSocketUtils.sendMessageAll(sendMap);
ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/SyncTask.java
@@ -3,12 +3,16 @@
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.device.camera.domain.ArdCameras;
import com.ruoyi.device.camera.domain.CameraCmd;
import com.ruoyi.device.camera.factory.CameraSDK;
import com.ruoyi.device.camera.factory.CameraSDKFactory;
import com.ruoyi.device.camera.service.IArdCamerasService;
import com.ruoyi.device.camera.service.ICameraSdkService;
import com.ruoyi.device.channel.domain.ArdChannel;
import com.ruoyi.device.channel.service.IArdChannelService;
import com.ruoyi.device.channel.service.impl.ArdChannelServiceImpl;
import com.ruoyi.media.domain.Vtdu;
import com.ruoyi.media.service.IMediaService;
import com.ruoyi.media.service.IVtduService;
@@ -21,6 +25,8 @@
import javax.annotation.Resource;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
/**
 * @Description: åŒæ­¥ä»»åŠ¡
@@ -43,6 +49,10 @@
    IMediaService mediaService;
    @Resource
    private ICameraSdkService cameraSdkService;
    @Resource
    private CameraSDKFactory cameraSDKFactory;
    @Resource
    private IArdChannelService ardChannelService;
    /**
     * åŒæ­¥ç›¸æœºåœ¨çº¿çŠ¶æ€
     * åˆ˜è‹ä¹‰
@@ -69,6 +79,34 @@
            }
        } catch (Exception ex) {
            log.error("同步相机在线状态异常:" + ex.getMessage());
        }
    }
    /**
     * @Author åˆ˜è‹ä¹‰
     * @Description åŒæ­¥nvr通道状态实时同步流媒体
     * @Date 2024/7/9 16:01
     */
    public void nvrChannelState() {
        //获取所有nvr设备
        List<ArdCameras> ardCamerasList = iArdCamerasService.selectArdCamerasListNoDataScope(new ArdCameras());
        if (ardCamerasList.size() > 0) {
            ardCamerasList.stream()
                    .filter(ardCameras -> ardCameras.getGdtype().equals("2"))
                    .forEach(ardCameras -> {
                        //通过SDK获取NVR当前通道
                        CameraSDK cameraSDK = cameraSDKFactory.createCameraSDK(ardCameras.getFactory());
                        List<ArdChannel> ardChannelList = cameraSDK.getChannels(ardCameras);
                        //同步通道表
                        ArdChannel ardChannel=new ArdChannel();
                        ardChannel.setDeviceId(ardCameras.getId());
                        List<ArdChannel> ardChannelListDb = ardChannelService.selectArdChannelList(ardChannel);
                        ardChannelService.asyncChannel(ardChannelListDb,ardChannelList);
                        //同步流媒体表
                        //同步流媒体api
                    });
        }
    }
@@ -105,13 +143,8 @@
     * 2023/10/13 14:13:53
     */
    public void vtdu() {
        List<Vtdu> vtdus = vtduService.selectVtduList(new Vtdu());
        for (Vtdu vtdu : vtdus) {
            boolean nameExist = mediaService.checkNameExist(vtdu.getName());
            if (!nameExist) {
                mediaService.addPath(vtdu.getName(), vtdu.getRtspSource(), vtdu.getMode(), vtdu.getIsCode());
            }
        }
        List<String> nameList = mediaService.getNameList();
        List<Vtdu> vtduList = vtduService.selectVtduList(new Vtdu());
        vtduService.asyncVtdu(vtduList,nameList);
    }
}