3 files added
24 files modified
| | |
| | | return R.fail("根据流id获取视频监控设备失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public R<QsDevice> getQsDeviceInfo(Long id, String inner) { |
| | | return R.fail("获取视频监控设备详细信息失败:" + throwable.getMessage()); |
| New file |
| | |
| | | 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); |
| | | |
| | | } |
| | |
| | | * 流地址 |
| | | */ |
| | | @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; |
| | | /** |
| | | * 通道流媒体信息 |
| | | */ |
| New file |
| | |
| | | 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()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | com.ard.work.api.factory.RemoteHealthFallbackFactory |
| | | com.ard.work.api.factory.RemoteTubesFallbackFactory |
| | | com.ard.work.api.factory.RemoteWellFallbackFactory |
| | | com.ard.work.api.factory.RemoteRadarFallbackFactory |
| | | com.ard.work.api.factory.RemoteRadarFallbackFactory |
| | | com.ard.work.api.factory.RemoteChannelFallbackFactory |
| | |
| | | package com.ard.zlm.api.domain; |
| | | |
| | | import lombok.AllArgsConstructor; |
| | | import lombok.Builder; |
| | | import lombok.Data; |
| | | import lombok.NoArgsConstructor; |
| | | |
| | | import java.io.Serializable; |
| | | |
| | |
| | | * @date 2026-04-02 |
| | | **/ |
| | | @Data |
| | | public class StreamPullPlay implements Serializable{ |
| | | @Builder |
| | | @AllArgsConstructor |
| | | @NoArgsConstructor |
| | | public class StreamPullPlay implements Serializable { |
| | | |
| | | /** |
| | | * 设备id |
| | | * 通道id |
| | | */ |
| | | private Long deviceId; |
| | | private String channelId; |
| | | |
| | | /** |
| | | * 应用名称 |
| | |
| | | /** |
| | | * 转协议时是否开启音频 |
| | | */ |
| | | 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:组播 |
| | |
| | | /** |
| | | * 超时时间 |
| | | */ |
| | | private int timeOut; |
| | | @Builder.Default |
| | | private int timeOut = 10; |
| | | |
| | | /** 当前拉流使用的流媒体服务ID */ |
| | | /** |
| | | * 当前拉流使用的流媒体服务ID |
| | | */ |
| | | private String mediaServerId; |
| | | |
| | | /** 拉流代理时zlm返回的key,用于停止拉流代理 */ |
| | | /** |
| | | * 拉流代理时zlm返回的key,用于停止拉流代理 |
| | | */ |
| | | private String streamKey; |
| | | } |
| | |
| | | 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 -> { |
| | |
| | | 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); |
| | | } |
| | |
| | | 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 { |
| New file |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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; |
| | | |
| | |
| | | public ArdChannel selectArdChannelById(String id); |
| | | |
| | | /** |
| | | * 根据设备id集合查询设备信息 |
| | | * |
| | | * @param startChannelIdList 设备id集合 |
| | | * @return |
| | | */ |
| | | List<ArdChannel> queryByIds(@Param("startChannelIdList") List<String> startChannelIdList); |
| | | /** |
| | | * 查询通道管理列表 |
| | | * |
| | | * @param ardChannel 通道管理 |
| | |
| | | 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; |
| | |
| | | public ArdChannel selectArdChannelById(String id); |
| | | |
| | | /** |
| | | * 根据设备id集合查询设备信息 |
| | | * |
| | | * @param startChannelIdList 设备id集合 |
| | | * @return |
| | | */ |
| | | public List<ArdChannel> queryByIds(List<String> startChannelIdList); |
| | | /** |
| | | * 查询通道管理列表 |
| | | * |
| | | * @param ardChannel 通道管理 |
| | |
| | | /** |
| | | * 查询通道管理列表 |
| | | * |
| | | * @param startChannelIdList 开始通道ID列表 |
| | | * @return 列表 |
| | | */ |
| | | @Override |
| | | public List<ArdChannel> queryByIds(List<String> startChannelIdList) { |
| | | return ardChannelMapper.queryByIds(startChannelIdList); |
| | | } |
| | | |
| | | /** |
| | | * 查询通道管理列表 |
| | | * |
| | | * @param ardChannel 通道管理 |
| | | * @return 通道管理 |
| | | */ |
| | |
| | | camera.getRtspPort(), |
| | | channel.getChanNo() |
| | | ); |
| | | channel.setRtspUrl(rtspUrl); |
| | | channel.setLiveAddress(rtspUrl); |
| | | ardChannelList.add(channel); |
| | | } |
| | | return ardChannelList; |
| | |
| | | camera.getRtspPort(), |
| | | 2 |
| | | ); |
| | | ardChannel.setRtspUrl(rtspUrl); |
| | | ardChannel.setLiveAddress(rtspUrl); |
| | | channelList.add(ardChannel); |
| | | } catch (Exception ex) { |
| | | log.error("获取IP通道异常:{}", ex.getMessage(), ex); |
| | |
| | | camera.getRtspPort(), |
| | | channel.getChanNo() |
| | | ); |
| | | channel.setRtspUrl(rtspUrl); |
| | | channel.setLiveAddress(rtspUrl); |
| | | channelList.add(channel); |
| | | } |
| | | } |
| | |
| | | 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 |
| | |
| | | channel.setVideoCode("h264"); // 写死通道编码格式 |
| | | // 【新增】构建 rtspUrl - 类型2 |
| | | String rtspUrl = buildRtspUrlForType2(node); |
| | | channel.setRtspUrl(rtspUrl); |
| | | channel.setLiveAddress(rtspUrl); |
| | | } |
| | | channelList.add(channel); |
| | | } |
| | |
| | | camera.getRtspPort(), |
| | | channel.getChanNo() - 1 |
| | | ); |
| | | channel.setRtspUrl(rtspUrl); |
| | | channel.setLiveAddress(rtspUrl); |
| | | channels.add(channel); |
| | | } |
| | | |
| | |
| | | <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> |
| | | |
| | |
| | | <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"> |
| | |
| | | <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> |
| | |
| | | <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> |
| | | |
| | |
| | | <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> |
| | |
| | | @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; |
| | |
| | | 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; |
| | |
| | | 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); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | /** |
| | | * 开始播放 |
| | | * |
| | | * @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); |
| | | |
| | | /** |
| | | * 获取流媒体服务器负载 |
| | |
| | | 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 ISourcePlayService { |
| | | |
| | | void play(QsDevice device, Boolean record, ErrorCallback<StreamInfo> callback); |
| | | void play(ArdChannel channel, Boolean record, ErrorCallback<StreamInfo> callback); |
| | | } |
| | |
| | | |
| | | 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; |
| | |
| | | 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); |
| | | }); |
| | | } |
| | |
| | | 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; |
| | |
| | | |
| | | @Resource |
| | | private RemoteQsDeviceService remoteQsDeviceService; |
| | | |
| | | @Resource |
| | | private RemoteChannelService remoteChannelService; |
| | | |
| | | @Resource |
| | | private ZLMRESTfulUtils zlmresTfulUtils; |
| | |
| | | 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); |
| | |
| | | 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()); |
| | |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | |
| | | 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("更新设备失败"); |
| | | } |
| | |
| | | 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; |
| | | } |
| | | |
| | |
| | | /** |
| | | * 开始播放 |
| | | * |
| | | * @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) { |
| | |
| | | } |
| | | |
| | | // 播放海康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); |
| | | // } |
| | | } |
| | | |
| | | /** |
| | |
| | | @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; |
| | | } |
| | | |
| | |
| | | |
| | | 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; |
| | |
| | | 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); |
| | | } |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | @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<>(); |
| | | |
| | | /** |
| | | * 流离开的处理 |
| | |
| | | @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); |
| | | } |
| | |
| | | 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) { |
| | |
| | | })); |
| | | } |
| | | |
| | | 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; |
| | |
| | | */ |
| | | @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)); |
| | | // } |
| | | // } |
| | | // } |
| | | } |
| | | |
| | | /** |
| | |
| | | * @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) { |
| | |
| | | } |
| | | |
| | | // 查看是否有人观看,存在则不做处理,等待后续自然处理,如果无人观看,则关闭该流 |
| | | 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) { |