liusuyi
2026-05-12 9f327c33730ba10cb2d89aff99b727502232e968
优化
3 files added
24 files modified
821 ■■■■■ changed files
ard-api/ard-api-qs/src/main/java/com/ard/qs/api/factory/RemoteQsDeviceFallbackFactory.java 1 ●●●● patch | view | raw | blame | history
ard-api/ard-api-work/src/main/java/com/ard/work/api/RemoteChannelService.java 67 ●●●●● patch | view | raw | blame | history
ard-api/ard-api-work/src/main/java/com/ard/work/api/domian/ArdChannel.java 11 ●●●● patch | view | raw | blame | history
ard-api/ard-api-work/src/main/java/com/ard/work/api/factory/RemoteChannelFallbackFactory.java 56 ●●●●● patch | view | raw | blame | history
ard-api/ard-api-work/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 1 ●●●● patch | view | raw | blame | history
ard-api/ard-api-zlm/src/main/java/com/ard/zlm/api/domain/StreamPullPlay.java 27 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/camera/service/impl/ArdCameraServiceImpl.java 6 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/api/ArdChannelApiController.java 77 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/mapper/ArdChannelMapper.java 9 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/service/IArdChannelService.java 8 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/service/impl/ArdChannelServiceImpl.java 11 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/dh/service/DaHuaSDK.java 2 ●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/fjr/service/FjrSDK.java 2 ●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hik/service/AbstractHikVisionSDK.java 2 ●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hp/service/HpSDK.java 4 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/zlxd/service/ZlxdSDK.java 2 ●●● patch | view | raw | blame | history
ard-modules/ard-modules-work/src/main/resources/mapper/device/ArdChannelMapper.xml 34 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/config/MediaConfig.java 4 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java 2 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/IDevicePlayService.java 3 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/IMediaServerService.java 5 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/ISourcePlayService.java 3 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/DevicePlayServiceImpl.java 9 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/MediaServerServiceImpl.java 154 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/MediaServiceImpl.java 108 ●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/SourcePlayServiceImpl.java 7 ●●●●● patch | view | raw | blame | history
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/ZlmRecordPlanServiceImpl.java 206 ●●●● patch | view | raw | blame | history
ard-api/ard-api-qs/src/main/java/com/ard/qs/api/factory/RemoteQsDeviceFallbackFactory.java
@@ -54,6 +54,7 @@
                return R.fail("根据流id获取视频监控设备失败:" + throwable.getMessage());
            }
            @Override
            public R<QsDevice> getQsDeviceInfo(Long id, String inner) {
                return R.fail("获取视频监控设备详细信息失败:" + throwable.getMessage());
ard-api/ard-api-work/src/main/java/com/ard/work/api/RemoteChannelService.java
New file
@@ -0,0 +1,67 @@
package com.ard.work.api;
import com.ard.common.core.constant.SecurityConstants;
import com.ard.common.core.constant.ServiceNameConstants;
import com.ard.common.core.domain.R;
import com.ard.common.core.web.domain.AjaxResult;
import com.ard.work.api.domian.ArdCamera;
import com.ard.work.api.domian.ArdChannel;
import com.ard.work.api.domian.CameraCmd;
import com.ard.work.api.factory.RemoteCameraFallbackFactory;
import com.ard.work.api.factory.RemoteChannelFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.TreeMap;
/**
 * 通道服务
 *
 * @author ard
 */
@FeignClient(contextId = "remoteChannelService", value = ServiceNameConstants.WORK_SERVICE, fallbackFactory =
        RemoteChannelFallbackFactory.class)
public interface RemoteChannelService {
    /**
     * 获取所有通道
     *
     * @return 结果
     */
    @GetMapping(value = "/api/device/channel/list")
    public R<List<ArdChannel>> list(@SpringQueryMap ArdChannel ardChannel,
                                    @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
    /**
     * 获取通道信息
     *
     * @param id
     * @return
     */
    @GetMapping("/api/device/channel/{id}")
    public R<ArdChannel> getInfo(@PathVariable("id") String id,
                                 @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
    /**
     * 根据通道id集合查询设备信息
     *
     * @param startChannelIdList 通道id集合
     * @param inner              请求来源
     * @return
     */
    @GetMapping("/api/device/queryByIds/{startChannelIdList}")
    R<List<ArdChannel>> queryByIds(@PathVariable List<String> startChannelIdList,
                                   @RequestHeader(SecurityConstants.FROM_SOURCE) String inner);
    /**
     * 修改通道信息
     *
     * @param ardChannel
     * @return
     */
    @PutMapping("/api/device/channel/updateArdChannel")
    public R<Boolean> update(@RequestBody ArdChannel ardChannel,
                             @RequestHeader(SecurityConstants.FROM_SOURCE) String source);
}
ard-api/ard-api-work/src/main/java/com/ard/work/api/domian/ArdChannel.java
@@ -54,8 +54,15 @@
     * 流地址
     */
    @Excel(name = "流地址")
    private String rtspUrl;
    private String liveAddress;
    /** 截图路径 */
    private String snapUrl;
    /** 直播流接入类型(1=RTSP,2=RTMP,3=FLV,4=HLS,5=ONVIF,6=视频文件,7=海康SDK,8=海康ISUP,9=大华SDK,10=宇视SDK,11=天地伟业SDK,12=国标28181,13=PUSH,14=部标1078) */
    private String type;
    /** 当前拉流使用的流媒体服务ID */
    private String mediaServerId;
    /** 拉流代理时zlm返回的key,用于停止拉流代理 */
    private String streamKey;
    /**
     * 通道流媒体信息
     */
ard-api/ard-api-work/src/main/java/com/ard/work/api/factory/RemoteChannelFallbackFactory.java
New file
@@ -0,0 +1,56 @@
package com.ard.work.api.factory;
import com.ard.common.core.domain.R;
import com.ard.common.core.web.domain.AjaxResult;
import com.ard.work.api.RemoteCameraService;
import com.ard.work.api.RemoteChannelService;
import com.ard.work.api.domian.ArdCamera;
import com.ard.work.api.domian.ArdChannel;
import com.ard.work.api.domian.CameraCmd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.TreeMap;
/**
 * 通道服务降级处理
 *
 * @author ard
 */
@Component
public class RemoteChannelFallbackFactory implements FallbackFactory<RemoteChannelService>
{
    private static final Logger log = LoggerFactory.getLogger(RemoteChannelFallbackFactory.class);
    @Override
    public RemoteChannelService create(Throwable throwable)
    {
        log.error("相机服务调用失败:{}", throwable.getMessage());
        return new RemoteChannelService()
        {
            @Override
            public R<List<ArdChannel>> list(ArdChannel ardChannel, String source) {
                return R.fail("获取通道列表失败:" + throwable.getMessage());
            }
            @Override
            public R<ArdChannel>  getInfo(String id, String source) {
                return R.fail("获取通道信息失败:" + throwable.getMessage());
            }
            @Override
            public R<List<ArdChannel>> queryByIds(List<String> startChannelIdList, String inner) {
                return R.fail("获取通道列表失败:" + throwable.getMessage());
            }
            @Override
            public R<Boolean> update(ArdChannel ardChannel, String source) {
                return R.fail("更新通道失败:" + throwable.getMessage());
            }
        };
    }
}
ard-api/ard-api-work/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -5,3 +5,4 @@
com.ard.work.api.factory.RemoteTubesFallbackFactory
com.ard.work.api.factory.RemoteWellFallbackFactory
com.ard.work.api.factory.RemoteRadarFallbackFactory
com.ard.work.api.factory.RemoteChannelFallbackFactory
ard-api/ard-api-zlm/src/main/java/com/ard/zlm/api/domain/StreamPullPlay.java
@@ -1,6 +1,9 @@
package com.ard.zlm.api.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@@ -13,12 +16,15 @@
 * @date 2026-04-02
 **/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class StreamPullPlay implements Serializable{
    /**
     * 设备id
     * 通道id
     */
    private Long deviceId;
    private String channelId;
    /**
     * 应用名称
@@ -38,12 +44,14 @@
    /**
     * 转协议时是否开启音频
     */
    private boolean enable_audio;
    @Builder.Default
    private boolean enable_audio = true;
    /**
     * 是否允许 mp4 录制
     */
    private boolean enable_mp4;
    @Builder.Default
    private boolean enable_mp4 = false;
    /**
     * rtsp 拉流时,拉流方式,0:tcp,1:udp,2:组播
@@ -53,11 +61,16 @@
    /**
     * 超时时间
     */
    private int timeOut;
    @Builder.Default
    private int timeOut = 10;
    /** 当前拉流使用的流媒体服务ID */
    /**
     * 当前拉流使用的流媒体服务ID
     */
    private String mediaServerId;
    /** 拉流代理时zlm返回的key,用于停止拉流代理 */
    /**
     * 拉流代理时zlm返回的key,用于停止拉流代理
     */
    private String streamKey;
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/camera/service/impl/ArdCameraServiceImpl.java
@@ -543,7 +543,7 @@
                    return oldChannel != null && (
                            !Objects.equals(channel.getName(), oldChannel.getName()) ||
                                    !Objects.equals(channel.getVideoCode(), oldChannel.getVideoCode()) ||
                                    !Objects.equals(channel.getRtspUrl(), oldChannel.getRtspUrl())  // 新增 rtspUrl 判断
                                    !Objects.equals(channel.getLiveAddress(), oldChannel.getLiveAddress())  // 新增 rtspUrl 判断
                    );
                })
                .forEach(channel -> {
@@ -571,7 +571,7 @@
                    if (ardChannelService.checkArdChannelUnique(channel)) {
                        ArdCamera camera = this.selectArdCameraById(channel.getDeviceId());
                        if(camera!=null) {
                            channel.setRtspUrl(getRtspUrl(camera, channel));
                            channel.setLiveAddress(getRtspUrl(camera, channel));
                        }
                        ardChannelService.insertArdChannel(channel);
                    }
@@ -617,7 +617,7 @@
        channelList.forEach(channel -> {
            ArdChannel dbChannel = dbMap.get(channel.getChanNo());
            if (dbChannel == null) {
                channel.setRtspUrl(getRtspUrl(camera,channel));
                channel.setLiveAddress(getRtspUrl(camera,channel));
                // 不存在 → 插入
                ardChannelService.insertArdChannel(channel);
            } else {
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/api/ArdChannelApiController.java
New file
@@ -0,0 +1,77 @@
package com.ard.work.device.channel.api;
import com.ard.common.core.domain.R;
import com.ard.common.core.utils.poi.ExcelUtil;
import com.ard.common.core.web.controller.BaseController;
import com.ard.common.core.web.domain.AjaxResult;
import com.ard.common.core.web.page.TableDataInfo;
import com.ard.common.log.annotation.Log;
import com.ard.common.log.enums.BusinessType;
import com.ard.common.security.annotation.InnerAuth;
import com.ard.common.security.annotation.RequiresPermissions;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.work.device.channel.service.IArdChannelService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
 * 通道管理Controller
 *
 * @author ard
 * @date 2023-08-19
 */
@RestController
@RequestMapping("/api/device/channel")
@Tag(name = "通道管理接口")
public class ArdChannelApiController extends BaseController {
    @Autowired
    private IArdChannelService ardChannelService;
    /**
     * 查询全部通道
     */
    @InnerAuth
    @GetMapping("/list")
    public  R<List<ArdChannel>> list(ArdChannel ardChannel) {
        List<ArdChannel> list = ardChannelService.selectArdChannelList(ardChannel);
        return R.ok(list);
    }
    /**
     * 获取通道管理详细信息
     */
    @InnerAuth
    @GetMapping(value = "/{id}")
    public R<ArdChannel> getInfo(@PathVariable("id") String id) {
        return R.ok(ardChannelService.selectArdChannelById(id));
    }
    /**
     * 根据通道id集合查询通道信息
     *
     * @param startChannelIdList 通道id集合
     * @return
     */
    @InnerAuth
    @GetMapping("/queryByIds/{startChannelIdList}")
    public R<List<ArdChannel>> queryByIds(@PathVariable List<String> startChannelIdList) {
        List<ArdChannel> channelList = ardChannelService.queryByIds(startChannelIdList);
        return R.ok(channelList);
    }
    /**
     * 修改通道管理
     */
    @InnerAuth
    @PutMapping("/updateArdChannel")
    public R<Boolean> updateArdChannel(@RequestBody ArdChannel ardChannel) {
        return ardChannelService.updateArdChannel(ardChannel) > 0 ? R.ok(true) : R.ok(false);
    }
}
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/mapper/ArdChannelMapper.java
@@ -1,6 +1,8 @@
package com.ard.work.device.channel.mapper;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@@ -21,6 +23,13 @@
    public ArdChannel selectArdChannelById(String id);
    /**
     * 根据设备id集合查询设备信息
     *
     * @param startChannelIdList 设备id集合
     * @return
     */
    List<ArdChannel> queryByIds(@Param("startChannelIdList") List<String> startChannelIdList);
    /**
     * 查询通道管理列表
     * 
     * @param ardChannel 通道管理
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/service/IArdChannelService.java
@@ -1,5 +1,6 @@
package com.ard.work.device.channel.service;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import java.util.List;
@@ -20,6 +21,13 @@
    public ArdChannel selectArdChannelById(String id);
    /**
     * 根据设备id集合查询设备信息
     *
     * @param startChannelIdList 设备id集合
     * @return
     */
    public List<ArdChannel> queryByIds(List<String> startChannelIdList);
    /**
     * 查询通道管理列表
     *
     * @param ardChannel 通道管理
ard-modules/ard-modules-work/src/main/java/com/ard/work/device/channel/service/impl/ArdChannelServiceImpl.java
@@ -53,6 +53,17 @@
    /**
     * 查询通道管理列表
     *
     * @param startChannelIdList 开始通道ID列表
     * @return 列表
     */
    @Override
    public List<ArdChannel> queryByIds(List<String> startChannelIdList) {
        return ardChannelMapper.queryByIds(startChannelIdList);
    }
    /**
     * 查询通道管理列表
     *
     * @param ardChannel 通道管理
     * @return 通道管理
     */
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/dh/service/DaHuaSDK.java
@@ -224,7 +224,7 @@
                    camera.getRtspPort(),
                    channel.getChanNo()
            );
            channel.setRtspUrl(rtspUrl);
            channel.setLiveAddress(rtspUrl);
            ardChannelList.add(channel);
        }
        return ardChannelList;
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/fjr/service/FjrSDK.java
@@ -317,7 +317,7 @@
                    camera.getRtspPort(),
                    2
            );
            ardChannel.setRtspUrl(rtspUrl);
            ardChannel.setLiveAddress(rtspUrl);
            channelList.add(ardChannel);
        } catch (Exception ex) {
            log.error("获取IP通道异常:{}", ex.getMessage(), ex);
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hik/service/AbstractHikVisionSDK.java
@@ -1891,7 +1891,7 @@
                        camera.getRtspPort(),
                        channel.getChanNo()
                );
                channel.setRtspUrl(rtspUrl);
                channel.setLiveAddress(rtspUrl);
                channelList.add(channel);
            }
        }
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/hp/service/HpSDK.java
@@ -1535,7 +1535,7 @@
                    channel.setVideoCode(videoCfg.getVideoEncType());
                }
                String rtspUrl = buildRtspUrlForType1(node, chanNo);
                channel.setRtspUrl(rtspUrl);
                channel.setLiveAddress(rtspUrl);
            } else if ("2".equals(node.getNodeType())) {
                channel.setDeviceId(camera.getId());       // 归属父设备 ID
@@ -1544,7 +1544,7 @@
                channel.setVideoCode("h264");              // 写死通道编码格式
                // 【新增】构建 rtspUrl - 类型2
                String rtspUrl = buildRtspUrlForType2(node);
                channel.setRtspUrl(rtspUrl);
                channel.setLiveAddress(rtspUrl);
            }
            channelList.add(channel);
        }
ard-modules/ard-modules-work/src/main/java/com/ard/work/sdk/zlxd/service/ZlxdSDK.java
@@ -1190,7 +1190,7 @@
                    camera.getRtspPort(),
                    channel.getChanNo() - 1
            );
            channel.setRtspUrl(rtspUrl);
            channel.setLiveAddress(rtspUrl);
            channels.add(channel);
        }
ard-modules/ard-modules-work/src/main/resources/mapper/device/ArdChannelMapper.xml
@@ -10,11 +10,15 @@
        <result property="chanNo" column="chan_no"/>
        <result property="videoCode" column="video_code"/>
        <result property="deviceId" column="device_id"/>
        <result property="rtspUrl" column="rtsp_url"/>
        <result property="type" column="type"/>
        <result property="liveAddress" column="live_address"/>
        <result property="snapUrl" column="snap_url"/>
        <result property="mediaServerId" column="media_server_id"/>
        <result property="streamKey" column="stream_key"/>
    </resultMap>
    <sql id="selectArdChannelVo">
        select id, name, chan_no, video_code, device_id
        select id, name, chan_no, video_code, device_id, type, live_address, snap_url, media_server_id, stream_key
        from ard_channel
    </sql>
@@ -24,6 +28,14 @@
            <if test="deviceId!=null">device_id=#{deviceId}</if>
        </where>
        order by chan_no
    </select>
    <select id="queryByIds" resultMap="ArdChannelResult">
        <include refid="selectArdChannelVo"/>
        where id in
        <foreach item="id" collection="startArdChannelIdList" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
    <select id="selectArdChannelById" parameterType="String" resultMap="ArdChannelResult">
@@ -48,7 +60,11 @@
            <if test="chanNo != null">chan_no,</if>
            <if test="videoCode != null">video_code,</if>
            <if test="deviceId != null">device_id,</if>
            <if test="rtspUrl != null">rtsp_url,</if>
            <if test="liveAddress != null">live_address,</if>
            <if test="snapUrl != null">snap_url,</if>
            <if test="type != null">type,</if>
            <if test="mediaServerId != null">media_server_id,</if>
            <if test="streamKey != null">stream_key,</if>
        </trim>
        <trim prefix="values (" suffix=")" suffixOverrides=",">
            <if test="id != null">#{id},</if>
@@ -56,7 +72,11 @@
            <if test="chanNo != null">#{chanNo},</if>
            <if test="videoCode != null">#{videoCode},</if>
            <if test="deviceId != null">#{deviceId},</if>
            <if test="rtspUrl != null">#{rtspUrl},</if>
            <if test="liveAddress != null">#{liveAddress},</if>
            <if test="snapUrl != null">#{snapUrl},</if>
            <if test="type != null">#{type},</if>
            <if test="mediaServerId != null">#{mediaServerId},</if>
            <if test="streamKey != null">#{streamKey},</if>
        </trim>
    </insert>
@@ -67,7 +87,11 @@
            <if test="chanNo != null">chan_no = #{chanNo},</if>
            <if test="videoCode != null">video_code = #{videoCode},</if>
            <if test="deviceId != null">device_id = #{deviceId},</if>
            <if test="rtspUrl != null">rtsp_url = #{rtspUrl},</if>
            <if test="liveAddress != null">live_address = #{liveAddress},</if>
            <if test="snapUrl != null">snap_url = #{snapUrl},</if>
            <if test="type != null">type = #{type},</if>
            <if test="mediaServerId != null">media_server_id = #{mediaServerId},</if>
            <if test="streamKey != null">stream_key = #{streamKey},</if>
        </trim>
        where id = #{id}
    </update>
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/config/MediaConfig.java
@@ -75,8 +75,8 @@
    @Value("${media.jtt-proxy-port:0}")
    private Integer jttProxyPort = 0;
    @Value("${media.rtsp-port:0}")
    private Integer rtspPort = 0;
    @Value("${media.rtsp-port:554}")
    private Integer rtspPort = 554;
    @Value("${media.rtsp-ssl-port:0}")
    private Integer rtspSSLPort = 0;
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/controller/ZlmController.java
@@ -23,6 +23,8 @@
import com.ard.zlm.service.IInviteStreamService;
import com.ard.zlm.service.IMediaServerService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/IDevicePlayService.java
@@ -1,9 +1,10 @@
package com.ard.zlm.service;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.StreamInfo;
public interface IDevicePlayService {
    void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback);
    void play(ArdChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
}
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/IMediaServerService.java
@@ -2,6 +2,7 @@
import com.ard.gb28181.api.domain.Device;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.*;
import com.ard.zlm.common.InviteSessionType;
import com.ard.zlm.domain.MediaServerLoad;
@@ -292,11 +293,11 @@
    /**
     * 开始播放
     *
     * @param device   设备信息
     * @param channel  通道信息
     * @param record   是否录制
     * @param callback 回调
     */
    void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback);
    void play(ArdChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
    /**
     * 获取流媒体服务器负载
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/ISourcePlayService.java
@@ -1,6 +1,7 @@
package com.ard.zlm.service;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.StreamInfo;
/**
@@ -8,5 +9,5 @@
 */
public interface ISourcePlayService {
    void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback);
    void play(ArdChannel channel, Boolean record, ErrorCallback<StreamInfo> callback);
}
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/DevicePlayServiceImpl.java
@@ -2,6 +2,7 @@
import com.ard.common.core.enums.LiveStreamType;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.StreamInfo;
import com.ard.zlm.service.ErrorCallback;
import com.ard.zlm.service.IDevicePlayService;
@@ -28,15 +29,15 @@
    public final static String PLAY_SERVICE = "sourceDevicePlayService";
    @Override
    public void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback) {
        log.info("[设备] 播放, 类型: {}", LiveStreamType.getByCode(device.getType()));
    public void play(ArdChannel channel, Boolean record, ErrorCallback<StreamInfo> callback) {
        log.info("[设备] 播放, 类型: {}", LiveStreamType.getByCode(channel.getType()));
        ISourcePlayService sourceChannelPlayService = sourcePlayServiceMap.get(PLAY_SERVICE);
        if (sourceChannelPlayService == null) {
            // 设备数据异常
            log.error("[点播通用设备] 类型编号: {} 不支持实时流预览", LiveStreamType.getByCode(device.getType()));
            log.error("[点播通用设备] 类型编号: {} 不支持实时流预览", LiveStreamType.getByCode(channel.getType()));
            throw new RuntimeException("Device not supported");
        }
        sourceChannelPlayService.play(device, record, (code, msg, data) -> {
        sourceChannelPlayService.play(channel, record, (code, msg, data) -> {
            callback.run(code, msg, data);
        });
    }
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/MediaServerServiceImpl.java
@@ -13,6 +13,8 @@
import com.ard.qs.api.RemoteQsDeviceService;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.RemoteCameraService;
import com.ard.work.api.RemoteChannelService;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.*;
import com.ard.zlm.api.hook.OriginType;
import com.ard.zlm.common.InviteErrorCode;
@@ -95,6 +97,9 @@
    @Resource
    private RemoteQsDeviceService remoteQsDeviceService;
    @Resource
    private RemoteChannelService remoteChannelService;
    @Resource
    private ZLMRESTfulUtils zlmresTfulUtils;
@@ -626,19 +631,14 @@
            callback.run(InviteErrorCode.FAIL.getCode(), "无可用的节点", null);
            return;
        }
//        R<QsDevice> devicer = remoteQsDeviceService.getQsDeviceInfo(streamPullPlay.getDeviceId(), SecurityConstants
//        .INNER);
//        if (devicer.getCode() != Constants.SUCCESS) {
//            throw new RuntimeException("获取设备信息失败" + streamPullPlay.getDeviceId());
//        }
//
//        if (devicer.getData() == null) {
//            throw new RuntimeException("设备不存在" + streamPullPlay.getDeviceId());
//        }
//
//        if ("OFFLINE".equals(devicer.getData().getDeviceStatus())) {
//            throw new RuntimeException("设备不在线" + streamPullPlay.getDeviceId());
//        }
        R<ArdChannel> channel = remoteChannelService.getInfo(streamPullPlay.getChannelId(), SecurityConstants.INNER);
        if (channel.getCode() != Constants.SUCCESS) {
            throw new RuntimeException("获取通道信息失败" + streamPullPlay.getChannelId());
        }
        if (channel.getData() == null) {
            throw new RuntimeException("通道不存在" + streamPullPlay.getChannelId());
        }
        StreamInfo stream = getStreamInfoByAppAndStreamWithCheck(streamPullPlay.getApp(), streamPullPlay.getStream(),
                mediaServer.getId(), null, false);
@@ -670,13 +670,13 @@
            callback.run(InviteErrorCode.SUCCESS.getCode(), InviteErrorCode.SUCCESS.getMsg(), streamInfo);
            subscribe.removeSubscribe(rtpHook);
//            QsDevice qsDevice = new QsDevice();
//            qsDevice.setId(streamPullPlay.getDeviceId());
//            qsDevice.setSnap(filePath);
//            R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER);
//            if (r.getCode() != Constants.SUCCESS) {
//                throw new RuntimeException("更新设备失败");
//            }
            ArdChannel ardChannel = new ArdChannel();
            ardChannel.setId(streamPullPlay.getChannelId());
            ardChannel.setSnapUrl(filePath);
            R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER);
            if (r.getCode() != Constants.SUCCESS) {
                throw new RuntimeException("更新设备失败");
            }
        });
        IMediaNodeServerService mediaNodeServerService = nodeServerServiceMap.get(mediaServer.getType());
@@ -688,16 +688,16 @@
        }
        String key = mediaNodeServerService.startProxy(mediaServer, streamPullPlay);
//        QsDevice qsDevice = new QsDevice();
//        qsDevice.setId(streamPullPlay.getDeviceId());
//        qsDevice.setStreamKey(key);
//        qsDevice.setMediaServerId(mediaServer.getId());
//        qsDevice.setStreamStatus("1");
//        R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER);
//        if (r.getCode() != Constants.SUCCESS) {
//            log.error("更新设备失败");
//            callback.run(InviteErrorCode.FAIL.getCode(), "更新设备失败", null);
//        }
        ArdChannel ardChannel = new ArdChannel();
        ardChannel.setId(streamPullPlay.getChannelId());
        ardChannel.setStreamKey(key);
        ardChannel.setMediaServerId(mediaServer.getId());
        //ardChannel.setStreamStatus("1");
        R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER);
        if (r.getCode() != Constants.SUCCESS) {
            log.error("更新设备失败");
            callback.run(InviteErrorCode.FAIL.getCode(), "更新设备失败", null);
        }
    }
    /**
@@ -769,12 +769,12 @@
        stopProxy(mediaServer, streamPullPlay.getStreamKey());
        QsDevice qsDevice = new QsDevice();
        qsDevice.setId(streamPullPlay.getDeviceId());
        qsDevice.setStreamKey("");
        qsDevice.setMediaServerId("");
        qsDevice.setStreamStatus("0");
        R<Boolean> r = remoteQsDeviceService.updateQsDevice(qsDevice, SecurityConstants.INNER);
        ArdChannel ardChannel = new ArdChannel();
        ardChannel.setId(streamPullPlay.getChannelId());
        ardChannel.setStreamKey("");
        ardChannel.setMediaServerId("");
       // ardChannel.setStreamStatus("0");
        R<Boolean> r = remoteChannelService.update(ardChannel, SecurityConstants.INNER);
        if (r.getCode() != Constants.SUCCESS) {
            throw new RuntimeException("更新设备失败");
        }
@@ -799,7 +799,7 @@
            throw new RuntimeException("[getSnap] 失败, mediaServer的类型: " + mediaServer.getType() + ",未找到对应的实现类");
        }
        String filePath = fileDomain + filePrefix + "/snap/" + fileName;
        mediaNodeServerService.getSnap(mediaServer, app, stream, 15, 1, this.filePath + "/snap", fileName);
        mediaNodeServerService.getSnap(mediaServer, app, stream, 30, 300, this.filePath + "/snap", fileName);
        return filePath;
    }
@@ -1421,12 +1421,12 @@
    /**
     * 开始播放
     *
     * @param device   设备信息
     * @param ardChannel   通道信息
     * @param record   是否录制
     * @param callback 回调
     */
    @Override
    public void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback) {
    public void play(ArdChannel ardChannel, Boolean record, ErrorCallback<StreamInfo> callback) {
        ZlmMediaServer mediaServer = getMediaServerForMinimumLoad(null);
        if (mediaServer == null) {
@@ -1435,57 +1435,57 @@
        }
        // 播放海康sdk/播放海康isup/播放大华sdk
        if (LiveStreamType.HIK_SDK.getCode().equals(device.getType()) || LiveStreamType.HIK_ISUP.getCode().equals(device.getType()) || LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) {
            RTPServerParam rtpServerParam = new RTPServerParam();
            if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())) {
                rtpServerParam.setApp("haikang");
            } else if (LiveStreamType.HIK_ISUP.getCode().equals(device.getType())) {
                rtpServerParam.setApp("haikang_isup");
            } else if (LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) {
                rtpServerParam.setApp("dahua");
            }
            rtpServerParam.setStreamId(device.getDeviceCode());
            rtpServerParam.setTcpMode(0);
            rtpServerParam.setType(device.getType());
            rtpServerParam.setId(device.getId());
            System.out.println(rtpServerParam);
            play(mediaServer, rtpServerParam, device, null, callback);
        if (LiveStreamType.HIK_SDK.getCode().equals(ardChannel.getType()) || LiveStreamType.HIK_ISUP.getCode().equals(ardChannel.getType()) || LiveStreamType.DAHUA_SDK.getCode().equals(ardChannel.getType())) {
//            RTPServerParam rtpServerParam = new RTPServerParam();
//            if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())) {
//                rtpServerParam.setApp("haikang");
//            } else if (LiveStreamType.HIK_ISUP.getCode().equals(device.getType())) {
//                rtpServerParam.setApp("haikang_isup");
//            } else if (LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())) {
//                rtpServerParam.setApp("dahua");
//            }
//
//            rtpServerParam.setStreamId(device.getDeviceCode());
//            rtpServerParam.setTcpMode(0);
//            rtpServerParam.setType(device.getType());
//            rtpServerParam.setId(device.getId());
//            System.out.println(rtpServerParam);
//            play(mediaServer, rtpServerParam, device, null, callback);
        }
        // rtsp/rtmp/flv/hls/onvif
        if (LiveStreamType.RTSP.getCode().equals(device.getType()) || LiveStreamType.RTMP.getCode().equals(device.getType()) || LiveStreamType.FLV.getCode().equals(device.getType()) || LiveStreamType.HLS.getCode().equals(device.getType()) || LiveStreamType.ONVIF.getCode().equals(device.getType())) {
        if (LiveStreamType.RTSP.getCode().equals(ardChannel.getType()) || LiveStreamType.RTMP.getCode().equals(ardChannel.getType()) || LiveStreamType.FLV.getCode().equals(ardChannel.getType()) || LiveStreamType.HLS.getCode().equals(ardChannel.getType()) || LiveStreamType.ONVIF.getCode().equals(ardChannel.getType())) {
            StreamPullPlay streamPullPlay = new StreamPullPlay();
            streamPullPlay.setDeviceId(device.getId());
            streamPullPlay.setStream(device.getDeviceCode());
            streamPullPlay.setUrl(device.getLiveAddress());
            streamPullPlay.setEnable_mp4("1".equals(device.getEnableMp4()));
            streamPullPlay.setEnable_audio("1".equals(device.getEnableAudio()));
            streamPullPlay.setChannelId(ardChannel.getId());
            streamPullPlay.setStream(ardChannel.getId());
            streamPullPlay.setUrl(ardChannel.getLiveAddress());
            streamPullPlay.setEnable_mp4(false);
            streamPullPlay.setEnable_audio(true);
            streamPullPlay.setRtp_type("1");
            streamPullPlay.setTimeOut(10);
            if (LiveStreamType.RTSP.getCode().equals(device.getType())) {
            if (LiveStreamType.RTSP.getCode().equals(ardChannel.getType())) {
                streamPullPlay.setApp("rtsp");
            } else if (LiveStreamType.RTMP.getCode().equals(device.getType())) {
                streamPullPlay.setApp("rtmp");
            } else if (LiveStreamType.FLV.getCode().equals(device.getType())) {
                streamPullPlay.setApp("flv");
                if ("ws".equals(device.getFlvType())) {
                    streamPullPlay.setUrl(convertWsToHttp(device.getLiveAddress()));
                }
            } else if (LiveStreamType.HLS.getCode().equals(device.getType())) {
                streamPullPlay.setApp("hls");
            } else if (LiveStreamType.ONVIF.getCode().equals(device.getType())) {
                streamPullPlay.setApp("onvif");
            }
            } else if (LiveStreamType.RTMP.getCode().equals(ardChannel.getType())) {
                streamPullPlay.setApp("rtmp");}
//            } else if (LiveStreamType.FLV.getCode().equals(device.getType())) {
//                streamPullPlay.setApp("flv");
//                if ("ws".equals(device.getFlvType())) {
//                    streamPullPlay.setUrl(convertWsToHttp(device.getLiveAddress()));
//                }
//            } else if (LiveStreamType.HLS.getCode().equals(device.getType())) {
//                streamPullPlay.setApp("hls");
//            } else if (LiveStreamType.ONVIF.getCode().equals(device.getType())) {
//                streamPullPlay.setApp("onvif");
//            }
            streamPullPlay(streamPullPlay, callback);
        }
        // 视频文件
        if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) {
            loadRecord(device.getId(), callback);
        }
//        if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) {
//            loadRecord(device.getId(), callback);
//        }
    }
    /**
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/MediaServiceImpl.java
@@ -51,60 +51,60 @@
    @Override
    public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) {
        R<QsDevice> r = remoteQsDeviceService.getQsDeviceStream(stream, SecurityConstants.INNER);
        if (r.getCode() != Constants.SUCCESS) {
            return false;
        }
        QsDevice data = r.getData();
        if (data == null) {
            return false;
        }
        // 拉流代理
        if ("rtsp".equals(app) || "rtmp".equals(app) || "flv".equals(app) || "hls".equals(app)) {
            if ("1".equals(data.getEnableDisableNoneReader())) {
                // 无人观看停用
                // 修改数据
                StreamPullPlay streamPullPlay = new StreamPullPlay();
                streamPullPlay.setDeviceId(data.getId());
                streamPullPlay.setStreamKey(data.getStreamKey());
                streamPullPlay.setMediaServerId(data.getMediaServerId());
                mediaServerService.stopStreamPullPlay(streamPullPlay);
                return true;
            } else {
                return false;
            }
        } else if ("haikang".equals(app) || "haikang_isup".equals(app) || "dahua".equals(app)) {
            if ("1".equals(data.getEnableDisableNoneReader())) {
                // 无人观看停用
                RTPServerParam rtpServerParam = new RTPServerParam();
                rtpServerParam.setId(data.getId());
                rtpServerParam.setType(data.getType());
                rtpServerParam.setStreamId(stream);
                mediaServerService.stopRtpPlay(rtpServerParam);
                return true;
            } else {
                return false;
            }
        } else if ("push".equals(app)) {
            if ("1".equals(data.getEnableDisableNoneReader())) {
                return true;
            } else {
                return false;
            }
        } else if ("gb28181".equals(app)) {
            if ("1".equals(data.getEnableDisableNoneReader())) {
                R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(data.getGbDeviceId(), SecurityConstants.INNER);
                if (deviceR.getCode() == Constants.SUCCESS && deviceR.getData() != null) {
                    mediaServerService.stopGb28181Play(InviteSessionType.PLAY, data, deviceR.getData(), data.getDeviceCode());
                }
                return true;
            } else {
                return false;
            }
        }
//        R<QsDevice> r = remoteQsDeviceService.getQsDeviceStream(stream, SecurityConstants.INNER);
//        if (r.getCode() != Constants.SUCCESS) {
//            return false;
//        }
//
//        QsDevice data = r.getData();
//        if (data == null) {
//            return false;
//        }
//
//        // 拉流代理
//        if ("rtsp".equals(app) || "rtmp".equals(app) || "flv".equals(app) || "hls".equals(app)) {
//            if ("1".equals(data.getEnableDisableNoneReader())) {
//                // 无人观看停用
//                // 修改数据
//                StreamPullPlay streamPullPlay = new StreamPullPlay();
//                streamPullPlay.setDeviceId(data.getId());
//                streamPullPlay.setStreamKey(data.getStreamKey());
//                streamPullPlay.setMediaServerId(data.getMediaServerId());
//
//                mediaServerService.stopStreamPullPlay(streamPullPlay);
//                return true;
//            } else {
//                return false;
//            }
//        } else if ("haikang".equals(app) || "haikang_isup".equals(app) || "dahua".equals(app)) {
//            if ("1".equals(data.getEnableDisableNoneReader())) {
//                // 无人观看停用
//                RTPServerParam rtpServerParam = new RTPServerParam();
//                rtpServerParam.setId(data.getId());
//                rtpServerParam.setType(data.getType());
//                rtpServerParam.setStreamId(stream);
//                mediaServerService.stopRtpPlay(rtpServerParam);
//                return true;
//            } else {
//                return false;
//            }
//        } else if ("push".equals(app)) {
//            if ("1".equals(data.getEnableDisableNoneReader())) {
//                return true;
//            } else {
//                return false;
//            }
//        } else if ("gb28181".equals(app)) {
//            if ("1".equals(data.getEnableDisableNoneReader())) {
//                R<Device> deviceR = remoteGb28181Service.getDeviceByDeviceId(data.getGbDeviceId(), SecurityConstants.INNER);
//                if (deviceR.getCode() == Constants.SUCCESS && deviceR.getData() != null) {
//                    mediaServerService.stopGb28181Play(InviteSessionType.PLAY, data, deviceR.getData(), data.getDeviceCode());
//                }
//                return true;
//            } else {
//                return false;
//            }
//        }
        return true;
    }
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/SourcePlayServiceImpl.java
@@ -2,6 +2,7 @@
import com.ard.common.core.constant.HttpStatus;
import com.ard.qs.api.domain.QsDevice;
import com.ard.work.api.domian.ArdChannel;
import com.ard.zlm.api.domain.StreamInfo;
import com.ard.zlm.service.ErrorCallback;
import com.ard.zlm.service.IMediaServerService;
@@ -26,11 +27,11 @@
    private IMediaServerService mediaServerService;
    @Override
    public void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback) {
    public void play(ArdChannel ardChannel, Boolean record, ErrorCallback<StreamInfo> callback) {
        try {
            mediaServerService.play(device, record, callback);
            mediaServerService.play(ardChannel, record, callback);
        } catch (Exception e) {
            log.error("[点播失败] {}({})", device.getDeviceName(), device.getId(), e);
            log.error("[点播失败] {}({})", ardChannel.getName(), ardChannel.getId(), e);
            callback.run(HttpStatus.ERROR, "播放失败", null);
        }
    }
ard-modules/ard-modules-zlm/src/main/java/com/ard/zlm/service/impl/ZlmRecordPlanServiceImpl.java
@@ -1,5 +1,7 @@
package com.ard.zlm.service.impl;
import com.ard.work.api.RemoteChannelService;
import com.ard.work.api.domian.ArdChannel;
import com.google.common.base.Joiner;
import com.ard.common.core.constant.HttpStatus;
import com.ard.common.core.constant.SecurityConstants;
@@ -21,6 +23,7 @@
import com.ard.zlm.service.IDevicePlayService;
import com.ard.zlm.service.IMediaServerService;
import com.ard.zlm.service.IZlmRecordPlanService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
@@ -41,23 +44,24 @@
@Service
@Transactional(rollbackFor = Exception.class)
public class ZlmRecordPlanServiceImpl implements IZlmRecordPlanService {
    @Autowired
    @Resource
    private ZlmRecordPlanMapper zlmRecordPlanMapper;
    @Autowired
    @Resource
    private ZlmRecordPlanItemMapper zlmRecordPlanItemMapper;
    @Autowired
    @Resource
    private RemoteQsDeviceService remoteQsDeviceService;
    @Autowired
    @Resource
    private RemoteChannelService remoteChannelService;
    @Resource
    private IMediaServerService mediaServerService;
    @Autowired
    @Resource
    private IDevicePlayService devicePlayService;
    Map<Long, StreamInfo> recordStreamMap = new HashMap<>();
    Map<String, StreamInfo> recordStreamMap = new HashMap<>();
    /**
     * 流离开的处理
@@ -66,17 +70,18 @@
    @EventListener
    public void onApplicationEvent(MediaDepartureEvent event) {
        // 流断开,检查是否还处于录像状态, 如果是则继续录像
        Long deviceId = recording(event.getApp(), event.getStream());
        String deviceId = recording(event.getApp(), event.getStream());
        if (deviceId == null) {
            return;
        }
        // 重新拉起
        R<QsDevice> r = remoteQsDeviceService.getQsDeviceInfo(deviceId, SecurityConstants.INNER);
        R<ArdChannel> r = remoteChannelService.getInfo(deviceId, SecurityConstants.INNER);
        //  R<QsDevice> r = remoteQsDeviceService.getQsDeviceInfo(deviceId, SecurityConstants.INNER);
        if (r.getCode() != HttpStatus.SUCCESS) {
            throw new RuntimeException("根据设备id查询设备信息失败");
        }
        QsDevice device = r.getData();
        ArdChannel device = r.getData();
        if (device == null) {
            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备不存在, id: {}", deviceId);
        }
@@ -86,10 +91,10 @@
            return;
        }
        if ("OFFLINE".equals(device.getDeviceStatus())) {
            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备不在线, id: {}", deviceId);
            return;
        }
//        if ("OFFLINE".equals(device.getDeviceStatus())) {
//            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备不在线, id: {}", deviceId);
//            return;
//        }
        // 开启点播,
        devicePlayService.play(device, true, ((code, msg, streamInfo) -> {
            if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) {
@@ -102,8 +107,8 @@
        }));
    }
    public Long recording(String app, String stream) {
        for (Long deviceId : recordStreamMap.keySet()) {
    public String recording(String app, String stream) {
        for (String deviceId : recordStreamMap.keySet()) {
            StreamInfo streamInfo = recordStreamMap.get(deviceId);
            if (streamInfo != null && streamInfo.getApp().equals(app) && streamInfo.getStream().equals(stream)) {
                return deviceId;
@@ -222,59 +227,60 @@
     */
    @Override
    public void task() {
        List<Long> startDeviceIdList = queryCurrentChannelRecord();
        if (startDeviceIdList.isEmpty()) {
            // 当前没有录像任务, 如果存在旧的正在录像的就移除
            if (!recordStreamMap.isEmpty()) {
                Set<Long> recordStreamSet = new HashSet<>(recordStreamMap.keySet());
                stopStreams(recordStreamSet, recordStreamMap);
                recordStreamMap.clear();
            }
        } else {
            // 当前存在录像任务, 获取正在录像中存在但是当前录制列表不存在的内容,进行停止; 获取正在录像中没有但是当前需录制的列表中存在的进行开启.
            Set<Long> recordStreamSet = new HashSet<>(recordStreamMap.keySet());
            startDeviceIdList.forEach(recordStreamSet::remove);
            if (!recordStreamSet.isEmpty()) {
                // 正在录像中存在但是当前录制列表不存在的内容,进行停止;
                stopStreams(recordStreamSet, recordStreamMap);
            }
            // 移除startDeviceIdList中已经在录像的部分, 剩下的都是需要新添加的(正在录像中没有但是当前需录制的列表中存在的进行开启)
            recordStreamMap.keySet().forEach(startDeviceIdList::remove);
            if (!startDeviceIdList.isEmpty()) {
                // 获取所有的关联的设备
                R<List<QsDevice>> r = remoteQsDeviceService.queryByIds(startDeviceIdList, SecurityConstants.INNER);
                if (r.getCode() != HttpStatus.SUCCESS) {
                    throw new RuntimeException("根据设备id集合查询设备信息失败");
                }
                List<QsDevice> deviceList = r.getData();
                if (!deviceList.isEmpty()) {
                    // 查找是否已经开启录像, 如果没有则开启录像
                    for (QsDevice device : deviceList) {
                        if ("OFFLINE".equals(device.getDeviceStatus())) {
                            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备不在线, id: {}", device.getId());
                            return;
                        }
                        if ("DEACTIVATE".equals(device.getStatus())) {
                            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备未启用, id: {}", device.getId());
                            return;
                        }
                        // 开启点播,
                        devicePlayService.play(device, true, ((code, msg, streamInfo) -> {
                            if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) {
                                log.info("[录像] 开启成功, 设备ID: {}", device.getId());
                                recordStreamMap.put(device.getId(), streamInfo);
                            } else {
                                log.info("[录像] 开启失败, 十分钟后重试,  设备ID: {}", device.getId());
                            }
                        }));
                    }
                } else {
                    log.error("[录制计划] 数据异常, 这些关联的设备已经不存在了: {}", Joiner.on(",").join(startDeviceIdList));
                }
            }
        }
//        List<String> startDeviceIdList = queryCurrentChannelRecord();
//        if (startDeviceIdList.isEmpty()) {
//            // 当前没有录像任务, 如果存在旧的正在录像的就移除
//            if (!recordStreamMap.isEmpty()) {
//                Set<String> recordStreamSet = new HashSet<>(recordStreamMap.keySet());
//                stopStreams(recordStreamSet, recordStreamMap);
//                recordStreamMap.clear();
//            }
//        } else {
//            // 当前存在录像任务, 获取正在录像中存在但是当前录制列表不存在的内容,进行停止; 获取正在录像中没有但是当前需录制的列表中存在的进行开启.
//            Set<String> recordStreamSet = new HashSet<>(recordStreamMap.keySet());
//            startDeviceIdList.forEach(recordStreamSet::remove);
//            if (!recordStreamSet.isEmpty()) {
//                // 正在录像中存在但是当前录制列表不存在的内容,进行停止;
//                stopStreams(recordStreamSet, recordStreamMap);
//            }
//
//            // 移除startDeviceIdList中已经在录像的部分, 剩下的都是需要新添加的(正在录像中没有但是当前需录制的列表中存在的进行开启)
//            recordStreamMap.keySet().forEach(startDeviceIdList::remove);
//            if (!startDeviceIdList.isEmpty()) {
//                // 获取所有的关联的设备
//              //  R<List<QsDevice>> r = remoteQsDeviceService.queryByIds(startDeviceIdList, SecurityConstants.INNER);
//                R<List<ArdChannel>> r = remoteChannelService.queryByIds(startDeviceIdList, SecurityConstants.INNER);
//                if (r.getCode() != HttpStatus.SUCCESS) {
//                    throw new RuntimeException("根据设备id集合查询设备信息失败");
//                }
//                List<ArdChannel> deviceList = r.getData();
//                if (!deviceList.isEmpty()) {
//                    // 查找是否已经开启录像, 如果没有则开启录像
//                    for (ArdChannel device : deviceList) {
////                        if ("OFFLINE".equals(device.getDeviceStatus())) {
////                            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备不在线, id: {}", device.getId());
////                            return;
////                        }
////
////                        if ("DEACTIVATE".equals(device.getStatus())) {
////                            log.warn("[录制计划] 流离开时拉起需要录像的流时, 发现设备未启用, id: {}", device.getId());
////                            return;
////                        }
//                        // 开启点播,
//                        devicePlayService.play(device, true, ((code, msg, streamInfo) -> {
//                            if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) {
//                                log.info("[录像] 开启成功, 设备ID: {}", device.getId());
//                                recordStreamMap.put(device.getId(), streamInfo);
//                            } else {
//                                log.info("[录像] 开启失败, 十分钟后重试,  设备ID: {}", device.getId());
//                            }
//                        }));
//                    }
//                } else {
//                    log.error("[录制计划] 数据异常, 这些关联的设备已经不存在了: {}", Joiner.on(",").join(startDeviceIdList));
//                }
//            }
//        }
    }
    /**
@@ -283,8 +289,8 @@
     * @param devices         设备ID列表
     * @param recordStreamMap 正在录制的流信息
     */
    private void stopStreams(Collection<Long> devices, Map<Long, StreamInfo> recordStreamMap) {
        for (Long deviceId : devices) {
    private void stopStreams(Collection<String> devices, Map<String, StreamInfo> recordStreamMap) {
        for (String deviceId : devices) {
            try {
                StreamInfo streamInfo = recordStreamMap.get(deviceId);
                if (streamInfo == null) {
@@ -292,50 +298,52 @@
                }
                // 查看是否有人观看,存在则不做处理,等待后续自然处理,如果无人观看,则关闭该流
                MediaInfo mediaInfo = mediaServerService.getMediaInfo(streamInfo.getMediaServer(), streamInfo.getApp(), streamInfo.getStream());
                MediaInfo mediaInfo = mediaServerService.getMediaInfo(streamInfo.getMediaServer(),
                        streamInfo.getApp(), streamInfo.getStream());
                if (mediaInfo.getReaderCount() == null || mediaInfo.getReaderCount() == 0) {
                    R<QsDevice> r = remoteQsDeviceService.getQsDeviceInfo(deviceId, SecurityConstants.INNER);
                    R<ArdChannel> r = remoteChannelService.getInfo(deviceId, SecurityConstants.INNER);
                    // R<QsDevice> r = remoteQsDeviceService.getQsDeviceInfo(deviceId, SecurityConstants.INNER);
                    if (r.getCode() != HttpStatus.SUCCESS) {
                        throw new RuntimeException("根据设备id查询设备信息失败");
                        throw new RuntimeException("根据通道id查询设备信息失败");
                    }
                    QsDevice device = r.getData();
                    if (device == null) {
                        throw new RuntimeException("设备不存在");
                    ArdChannel ardChannel = r.getData();
                    if (ardChannel == null) {
                        throw new RuntimeException("通道不存在");
                    }
                    // 播放海康sdk/播放海康isup/播放大华sdk
                    if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())
                            || LiveStreamType.HIK_ISUP.getCode().equals(device.getType())
                            || LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())
                    ) {
                        RTPServerParam rtpServerParam = new RTPServerParam();
                        rtpServerParam.setType(device.getType());
                        rtpServerParam.setStreamId(device.getDeviceCode());
                        rtpServerParam.setId(device.getId());
                        mediaServerService.stopRtpPlay(rtpServerParam);
                    }
//                    if (LiveStreamType.HIK_SDK.getCode().equals(device.getType())
//                            || LiveStreamType.HIK_ISUP.getCode().equals(device.getType())
//                            || LiveStreamType.DAHUA_SDK.getCode().equals(device.getType())
//                    ) {
//                        RTPServerParam rtpServerParam = new RTPServerParam();
//                        rtpServerParam.setType(device.getType());
//                        rtpServerParam.setStreamId(device.getDeviceCode());
//                        rtpServerParam.setId(device.getId());
//
//                        mediaServerService.stopRtpPlay(rtpServerParam);
//                    }
                    // rtsp/rtmp/flv/hls/onvif
                    if (LiveStreamType.RTSP.getCode().equals(device.getType())
                            || LiveStreamType.RTMP.getCode().equals(device.getType())
                            || LiveStreamType.FLV.getCode().equals(device.getType())
                            || LiveStreamType.HLS.getCode().equals(device.getType())
                            || LiveStreamType.ONVIF.getCode().equals(device.getType())
                    if (LiveStreamType.RTSP.getCode().equals(ardChannel.getType())
                            || LiveStreamType.RTMP.getCode().equals(ardChannel.getType())
                            || LiveStreamType.FLV.getCode().equals(ardChannel.getType())
                            || LiveStreamType.HLS.getCode().equals(ardChannel.getType())
                            || LiveStreamType.ONVIF.getCode().equals(ardChannel.getType())
                    ) {
                        StreamPullPlay streamPullPlay = new StreamPullPlay();
                        streamPullPlay.setDeviceId(device.getId());
                        streamPullPlay.setMediaServerId(device.getMediaServerId());
                        streamPullPlay.setStreamKey(device.getStreamKey());
                        streamPullPlay.setChannelId(ardChannel.getId());
                        streamPullPlay.setMediaServerId(ardChannel.getMediaServerId());
                        streamPullPlay.setStreamKey(ardChannel.getStreamKey());
                        mediaServerService.stopStreamPullPlay(streamPullPlay);
                    }
                    // 视频文件
                    if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) {
                        mediaServerService.closeStreams(device.getId());
                    }
//                    if (LiveStreamType.VIDEO_FILE.getCode().equals(device.getType())) {
//                        mediaServerService.closeStreams(device.getId());
//                    }
                    log.info("[录制计划] 停止, 设备ID: {}", deviceId);
                }
            } catch (Exception e) {