From a2e7e8ff9cfaa69b001d483710bddbda50d55c91 Mon Sep 17 00:00:00 2001
From: liusuyi <1951119284@qq.com>
Date: Mon, 01 Jun 2026 16:14:19 +0800
Subject: [PATCH] 优化

---
 ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java |  288 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 288 insertions(+), 0 deletions(-)

diff --git a/ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java b/ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java
index fb017db..6f325da 100644
--- a/ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java
+++ b/ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java
@@ -10,6 +10,7 @@
 import com.ard.gb28181.api.RemoteGb28181Service;
 import com.ard.gb28181.api.domain.Device;
 import com.ard.gb28181.api.domain.DeviceChannel;
+import com.ard.gb28181.api.domain.GbChannelDTO;
 import com.ard.qs.api.RemoteQsDeviceService;
 import com.ard.qs.api.domain.QsDevice;
 import com.ard.work.api.RemoteCameraService;
@@ -492,6 +493,7 @@
      * @param id      设备id
      * @return
      */
+    @Operation(summary = "gb28181播放")
     @GetMapping("/startGb28181Play/{id}")
     public DeferredResult<R<StreamContent>> startGb28181Play(
             HttpServletRequest request,
@@ -633,4 +635,290 @@
         return AjaxResult.success(json);
     }
 
+    /**
+     * gb28181 播放(基于GbDevice,不依赖QS,按国标编码播放)
+     *
+     * @param request
+     * @param gbDeviceId  国标设备编码
+     * @param gbChannelId 国标通道编码
+     * @return
+     */
+    @Operation(summary = "gb28181播放(按国标编码)")
+    @GetMapping("/startGb28181PlayByGbDeviceId/{gbDeviceId}/{gbChannelId}")
+    public DeferredResult<R<StreamContent>> startGb28181PlayByGbDeviceId(
+            HttpServletRequest request,
+            @PathVariable String gbDeviceId,
+            @PathVariable String gbChannelId
+    ) {
+        log.info("[gb28181 开始点播] gbDeviceId:{}, gbChannelId:{}", gbDeviceId, gbChannelId);
+        Assert.hasText(gbDeviceId, "国标设备编码不可为空");
+        Assert.hasText(gbChannelId, "国标通道编码不可为空");
+
+        // 1. 查询 GbChannel 配置
+        R<GbChannelDTO> channelR = remoteGb28181Service.getGbChannel(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (channelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("获取GbChannel配置失败 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId
+                    + "。设备注册后会自动创建,请确认设备已上线并完成目录同步。");
+        }
+        Assert.notNull(channelR.getData(), "GbChannel不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+
+        GbChannelDTO gbChannelDTO = channelR.getData();
+
+        // 2. 查询国标设备
+        R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(gbDeviceId, SecurityConstants.INNER);
+        if (deviceR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备信息失败 deviceId:" + gbDeviceId);
+        }
+        Assert.notNull(deviceR.getData(), "gb28181 国标设备不存在 deviceId:" + gbDeviceId);
+
+        if (!deviceR.getData().isOnLine()) {
+            throw new RuntimeException("gb28181 国标设备不在线 deviceId:" + gbDeviceId);
+        }
+
+        // 3. 查询国标通道
+        R<DeviceChannel> deviceChannelR = remoteGb28181Service.getDeviceChannelByChannelId(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (deviceChannelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备通道失败 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+        Assert.notNull(deviceChannelR.getData(), "gb28181 国标设备通道不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+
+        if (!"ON".equals(deviceChannelR.getData().getStatus())) {
+            throw new RuntimeException("gb28181 国标设备通道不在线 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+
+        DeferredResult<R<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
+
+        result.onTimeout(() -> {
+            log.info("[点播等待超时] gbDeviceId:{}, gbChannelId:{}", gbDeviceId, gbChannelId);
+            R<StreamContent> fail = R.fail();
+            fail.setMsg("点播超时");
+            result.setResult(fail);
+
+            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, gbChannelDTO.getId());
+            mediaServerService.stopGb28181PlayByGbChannel(InviteSessionType.PLAY, gbChannelDTO, deviceR.getData(), gbChannelDTO.getDeviceCode());
+        });
+
+        ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
+            if (code == InviteErrorCode.SUCCESS.getCode()) {
+                R<StreamContent> r = R.ok();
+                if (streamInfo != null) {
+                    if (userSetting.getUseSourceIpAsStreamIp()) {
+                        streamInfo = streamInfo.clone();
+                        String host;
+                        try {
+                            URL url = new URL(request.getRequestURL().toString());
+                            host = url.getHost();
+                        } catch (MalformedURLException e) {
+                            host = request.getLocalAddr();
+                        }
+                        streamInfo.changeStreamIp(host);
+                    }
+                    if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
+                            && !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
+                        streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
+                    }
+                    r.setData(new StreamContent(streamInfo));
+                } else {
+                    r.setCode(code);
+                    r.setMsg(msg);
+                }
+                result.setResult(r);
+            } else {
+                result.setResult(R.fail(code, msg));
+            }
+        };
+
+        mediaServerService.startGb28181PlayByGbChannel(gbChannelDTO, deviceR.getData(), callback);
+        return result;
+    }
+
+    /**
+     * gb28181 停止点播(基于GbDevice,不依赖QS,按国标编码停止)
+     *
+     * @param gbDeviceId  国标设备编码
+     * @param gbChannelId 国标通道编码
+     * @return
+     */
+    @Operation(summary = "gb28181停止点播(按国标编码)")
+    @GetMapping("/stopGb28181PlayByGbDeviceId/{gbDeviceId}/{gbChannelId}")
+    public AjaxResult stopGb28181PlayByGbDeviceId(
+            @PathVariable String gbDeviceId,
+            @PathVariable String gbChannelId
+    ) {
+        log.info("[gb28181 停止点播] gbDeviceId:{}, gbChannelId:{}", gbDeviceId, gbChannelId);
+        Assert.hasText(gbDeviceId, "国标设备编码不可为空");
+        Assert.hasText(gbChannelId, "国标通道编码不可为空");
+
+        // 1. 查询 GbChannel 配置
+        R<GbChannelDTO> channelR = remoteGb28181Service.getGbChannel(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (channelR.getCode() != Constants.SUCCESS || channelR.getData() == null) {
+            throw new RuntimeException("GbChannel不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+
+        GbChannelDTO gbChannelDTO = channelR.getData();
+
+        // 2. 查询国标设备
+        R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(gbDeviceId, SecurityConstants.INNER);
+        if (deviceR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备信息失败 deviceId:" + gbDeviceId);
+        }
+        Assert.notNull(deviceR.getData(), "gb28181 国标设备不存在 deviceId:" + gbDeviceId);
+
+        // 3. 查询国标通道
+        R<DeviceChannel> deviceChannelR = remoteGb28181Service.getDeviceChannelByChannelId(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (deviceChannelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备通道失败 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+        Assert.notNull(deviceChannelR.getData(), "gb28181 国标设备通道不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+
+        mediaServerService.stopGb28181PlayByGbChannel(InviteSessionType.PLAY, gbChannelDTO,
+                deviceR.getData(), gbChannelDTO.getDeviceCode());
+
+        JSONObject json = new JSONObject();
+        json.put("gbDeviceId", gbDeviceId);
+        json.put("gbChannelId", gbChannelId);
+        return AjaxResult.success(json);
+    }
+
+    /**
+     * gb28181 播放(基于GbChannel主键ID)
+     *
+     * @param request
+     * @param channelId GbChannel主键ID
+     * @return
+     */
+    @Operation(summary = "gb28181播放(按通道主键ID)")
+    @GetMapping("/startGb28181PlayByChannelId/{channelId}")
+    public DeferredResult<R<StreamContent>> startGb28181PlayByChannelId(
+            HttpServletRequest request,
+            @PathVariable Long channelId
+    ) {
+        log.info("[gb28181 开始点播] channelId:{}", channelId);
+        Assert.notNull(channelId, "通道ID不可为空");
+
+        // 1. 根据主键ID查询 GbChannel
+        R<GbChannelDTO> channelR = remoteGb28181Service.getGbChannelById(channelId, SecurityConstants.INNER);
+        if (channelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("获取GbChannel失败 channelId:" + channelId);
+        }
+        Assert.notNull(channelR.getData(), "GbChannel不存在 channelId:" + channelId);
+
+        GbChannelDTO gbChannelDTO = channelR.getData();
+        String gbDeviceId = gbChannelDTO.getGbDeviceId();
+        String gbChannelId = gbChannelDTO.getGbChannelId();
+
+        // 2. 查询国标设备
+        R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(gbDeviceId, SecurityConstants.INNER);
+        if (deviceR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备信息失败 deviceId:" + gbDeviceId);
+        }
+        Assert.notNull(deviceR.getData(), "gb28181 国标设备不存在 deviceId:" + gbDeviceId);
+
+        if (!deviceR.getData().isOnLine()) {
+            throw new RuntimeException("gb28181 国标设备不在线 deviceId:" + gbDeviceId);
+        }
+
+        // 3. 查询国标通道
+        R<DeviceChannel> deviceChannelR = remoteGb28181Service.getDeviceChannelByChannelId(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (deviceChannelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备通道失败 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+        Assert.notNull(deviceChannelR.getData(), "gb28181 国标设备通道不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+
+        if (!"ON".equals(deviceChannelR.getData().getStatus())) {
+            throw new RuntimeException("gb28181 国标设备通道不在线 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+
+        DeferredResult<R<StreamContent>> result = new DeferredResult<>(userSetting.getPlayTimeout().longValue());
+
+        result.onTimeout(() -> {
+            log.info("[点播等待超时] channelId:{}, gbDeviceId:{}, gbChannelId:{}", channelId, gbDeviceId, gbChannelId);
+            R<StreamContent> fail = R.fail();
+            fail.setMsg("点播超时");
+            result.setResult(fail);
+
+            inviteStreamService.removeInviteInfoByDeviceAndChannel(InviteSessionType.PLAY, gbChannelDTO.getId());
+            mediaServerService.stopGb28181PlayByGbChannel(InviteSessionType.PLAY, gbChannelDTO, deviceR.getData(), gbChannelDTO.getDeviceCode());
+        });
+
+        ErrorCallback<StreamInfo> callback = (code, msg, streamInfo) -> {
+            if (code == InviteErrorCode.SUCCESS.getCode()) {
+                R<StreamContent> r = R.ok();
+                if (streamInfo != null) {
+                    if (userSetting.getUseSourceIpAsStreamIp()) {
+                        streamInfo = streamInfo.clone();
+                        String host;
+                        try {
+                            URL url = new URL(request.getRequestURL().toString());
+                            host = url.getHost();
+                        } catch (MalformedURLException e) {
+                            host = request.getLocalAddr();
+                        }
+                        streamInfo.changeStreamIp(host);
+                    }
+                    if (!ObjectUtils.isEmpty(streamInfo.getMediaServer().getTranscodeSuffix())
+                            && !"null".equalsIgnoreCase(streamInfo.getMediaServer().getTranscodeSuffix())) {
+                        streamInfo.setStream(streamInfo.getStream() + "_" + streamInfo.getMediaServer().getTranscodeSuffix());
+                    }
+                    r.setData(new StreamContent(streamInfo));
+                } else {
+                    r.setCode(code);
+                    r.setMsg(msg);
+                }
+                result.setResult(r);
+            } else {
+                result.setResult(R.fail(code, msg));
+            }
+        };
+
+        mediaServerService.startGb28181PlayByGbChannel(gbChannelDTO, deviceR.getData(), callback);
+        return result;
+    }
+
+    /**
+     * gb28181 停止点播(基于GbChannel主键ID)
+     *
+     * @param channelId GbChannel主键ID
+     * @return
+     */
+    @Operation(summary = "gb28181停止点播(按通道主键ID)")
+    @GetMapping("/stopGb28181PlayByChannelId/{channelId}")
+    public AjaxResult stopGb28181PlayByChannelId(@PathVariable Long channelId) {
+        log.info("[gb28181 停止点播] channelId:{}", channelId);
+        Assert.notNull(channelId, "通道ID不可为空");
+
+        // 1. 根据主键ID查询 GbChannel
+        R<GbChannelDTO> channelR = remoteGb28181Service.getGbChannelById(channelId, SecurityConstants.INNER);
+        if (channelR.getCode() != Constants.SUCCESS || channelR.getData() == null) {
+            throw new RuntimeException("GbChannel不存在 channelId:" + channelId);
+        }
+
+        GbChannelDTO gbChannelDTO = channelR.getData();
+        String gbDeviceId = gbChannelDTO.getGbDeviceId();
+        String gbChannelId = gbChannelDTO.getGbChannelId();
+
+        // 2. 查询国标设备
+        R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(gbDeviceId, SecurityConstants.INNER);
+        if (deviceR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备信息失败 deviceId:" + gbDeviceId);
+        }
+        Assert.notNull(deviceR.getData(), "gb28181 国标设备不存在 deviceId:" + gbDeviceId);
+
+        // 3. 查询国标通道
+        R<DeviceChannel> deviceChannelR = remoteGb28181Service.getDeviceChannelByChannelId(gbDeviceId, gbChannelId, SecurityConstants.INNER);
+        if (deviceChannelR.getCode() != Constants.SUCCESS) {
+            throw new RuntimeException("gb28181 获取设备通道失败 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+        }
+        Assert.notNull(deviceChannelR.getData(), "gb28181 国标设备通道不存在 gbDeviceId:" + gbDeviceId + " gbChannelId:" + gbChannelId);
+
+        mediaServerService.stopGb28181PlayByGbChannel(InviteSessionType.PLAY, gbChannelDTO,
+                deviceR.getData(), gbChannelDTO.getDeviceCode());
+
+        JSONObject json = new JSONObject();
+        json.put("channelId", channelId);
+        json.put("gbDeviceId", gbDeviceId);
+        json.put("gbChannelId", gbChannelId);
+        return AjaxResult.success(json);
+    }
+
 }

--
Gitblit v1.9.3