diff --git a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java index 2f636a4d..d14ba09c 100644 --- a/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/gb28181/dao/CommonGBChannelMapper.java @@ -498,6 +498,7 @@ public interface CommonGBChannelMapper { " wdc.stream_proxy_id,\n" + " wdc.create_time,\n" + " wdc.update_time,\n" + + " wdc.record_plan_id,\n" + " coalesce( wdc.gb_device_id, wdc.device_id) as gb_device_id,\n" + " coalesce( wdc.gb_name, wdc.name) as gb_name,\n" + " coalesce( wdc.gb_manufacturer, wdc.manufacturer) as gb_manufacturer,\n" + @@ -548,4 +549,53 @@ public interface CommonGBChannelMapper { List queryForRecordPlanForWebList(@Param("planId") Integer planId, @Param("query") String query, @Param("channelType") Integer channelType, @Param("online") Boolean online, @Param("hasLink") Boolean hasLink); + + @Select("") + List queryForRecordPlan(List planIdList); } diff --git a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java index 33f9856f..3777e19e 100755 --- a/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java +++ b/src/main/java/com/genersoft/iot/vmp/media/zlm/dto/hook/HookResultForOnPublish.java @@ -1,7 +1,11 @@ package com.genersoft.iot.vmp.media.zlm.dto.hook; import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; +import lombok.Getter; +import lombok.Setter; +@Setter +@Getter public class HookResultForOnPublish extends HookResult{ private boolean enable_audio; @@ -34,54 +38,6 @@ public class HookResultForOnPublish extends HookResult{ setMsg(msg); } - public boolean isEnable_audio() { - return enable_audio; - } - - public void setEnable_audio(boolean enable_audio) { - this.enable_audio = enable_audio; - } - - public boolean isEnable_mp4() { - return enable_mp4; - } - - public void setEnable_mp4(boolean enable_mp4) { - this.enable_mp4 = enable_mp4; - } - - public int getMp4_max_second() { - return mp4_max_second; - } - - public void setMp4_max_second(int mp4_max_second) { - this.mp4_max_second = mp4_max_second; - } - - public String getMp4_save_path() { - return mp4_save_path; - } - - public void setMp4_save_path(String mp4_save_path) { - this.mp4_save_path = mp4_save_path; - } - - public String getStream_replace() { - return stream_replace; - } - - public void setStream_replace(String stream_replace) { - this.stream_replace = stream_replace; - } - - public Integer getModify_stamp() { - return modify_stamp; - } - - public void setModify_stamp(Integer modify_stamp) { - this.modify_stamp = modify_stamp; - } - @Override public String toString() { return "HookResultForOnPublish{" + diff --git a/src/main/java/com/genersoft/iot/vmp/service/IRecordPlanService.java b/src/main/java/com/genersoft/iot/vmp/service/IRecordPlanService.java index 359e0072..abec8e0c 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/IRecordPlanService.java +++ b/src/main/java/com/genersoft/iot/vmp/service/IRecordPlanService.java @@ -1,7 +1,6 @@ package com.genersoft.iot.vmp.service; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; -import com.genersoft.iot.vmp.gb28181.bean.PlatformChannel; import com.genersoft.iot.vmp.service.bean.RecordPlan; import com.github.pagehelper.PageInfo; @@ -27,4 +26,6 @@ public interface IRecordPlanService { void linkAll(Integer planId); void cleanAll(Integer planId); + + boolean recording(String app, String stream); } diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java index ad575042..0959c784 100755 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/MediaServiceImpl.java @@ -15,6 +15,7 @@ import com.genersoft.iot.vmp.media.bean.MediaServer; import com.genersoft.iot.vmp.media.bean.ResultForOnPublish; import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo; import com.genersoft.iot.vmp.service.IMediaService; +import com.genersoft.iot.vmp.service.IRecordPlanService; import com.genersoft.iot.vmp.service.IUserService; import com.genersoft.iot.vmp.storager.IRedisCatchStorage; import com.genersoft.iot.vmp.streamProxy.bean.StreamProxy; @@ -59,6 +60,9 @@ public class MediaServiceImpl implements IMediaService { @Autowired private SipInviteSessionManager sessionManager; + @Autowired + private IRecordPlanService recordPlanService; + @Override public boolean authenticatePlay(String app, String stream, String callId) { if (app == null || stream == null) { @@ -205,6 +209,9 @@ public class MediaServiceImpl implements IMediaService { @Override public boolean closeStreamOnNoneReader(String mediaServerId, String app, String stream, String schema) { boolean result = false; + if (recordPlanService.recording(app, stream)) { + return false; + } // 国标类型的流 if ("rtp".equals(app)) { result = userSetting.getStreamOnDemand(); diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java index 061769b8..4bcc945a 100644 --- a/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java +++ b/src/main/java/com/genersoft/iot/vmp/service/impl/RecordPlanServiceImpl.java @@ -1,12 +1,15 @@ package com.genersoft.iot.vmp.service.impl; +import com.genersoft.iot.vmp.common.StreamInfo; import com.genersoft.iot.vmp.conf.exception.ControllerException; import com.genersoft.iot.vmp.gb28181.bean.CommonGBChannel; import com.genersoft.iot.vmp.gb28181.dao.CommonGBChannelMapper; -import com.genersoft.iot.vmp.gb28181.service.IGbChannelService; -import com.genersoft.iot.vmp.media.event.media.MediaArrivalEvent; +import com.genersoft.iot.vmp.gb28181.service.IGbChannelPlayService; +import com.genersoft.iot.vmp.media.bean.MediaInfo; import com.genersoft.iot.vmp.media.event.media.MediaDepartureEvent; +import com.genersoft.iot.vmp.media.service.IMediaServerService; import com.genersoft.iot.vmp.service.IRecordPlanService; +import com.genersoft.iot.vmp.service.bean.InviteErrorCode; import com.genersoft.iot.vmp.service.bean.RecordPlan; import com.genersoft.iot.vmp.service.bean.RecordPlanItem; import com.genersoft.iot.vmp.storager.dao.RecordPlanMapper; @@ -22,8 +25,8 @@ import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; +import java.time.LocalDateTime; +import java.util.*; @Service @Slf4j @@ -36,17 +39,12 @@ public class RecordPlanServiceImpl implements IRecordPlanService { private CommonGBChannelMapper channelMapper; @Autowired - private IGbChannelService channelService; + private IGbChannelPlayService channelPlayService; + + @Autowired + private IMediaServerService mediaServerService; - /** - * 流到来的处理 - */ - @Async("taskExecutor") - @org.springframework.context.event.EventListener - public void onApplicationEvent(MediaArrivalEvent event) { - - } /** * 流离开的处理 @@ -55,23 +53,89 @@ public class RecordPlanServiceImpl implements IRecordPlanService { @EventListener public void onApplicationEvent(MediaDepartureEvent event) { // 流断开,检查是否还处于录像状态, 如果是则继续录像 + if (recording(event.getApp(), event.getStream())) { + // 重新拉起 + } } + Map recordStreamMap = new HashMap<>(); + @Scheduled(cron = "0 */30 * * * *") public void execution() { // 执行计划 + + // 获取当前时间在一周内的序号 + LocalDateTime now = LocalDateTime.now(); + int week = now.getDayOfWeek().getValue(); + int index = now.getHour() * 2 + (now.getMinute() > 30?1:0); // 查询startTime等于现在的, 开始录像 + List startPlanList = recordPlanMapper.queryStart(week, index); - // 查询stopTime等于现在的,结束录像 - // 查询处于中间的,验证录像是否正在进行 - - - // TODO 无人观看要确保处于录像状态的通道不被移除 + Map channelMapWithoutRecord = new HashMap<>(); + if (startPlanList.isEmpty()) { + // 停止所有正在录像的 + if(recordStreamMap.isEmpty()) { + // 暂无录像任务 + return; + }else { + channelMapWithoutRecord.putAll(recordStreamMap); + recordStreamMap.clear(); + } + }else { + channelMapWithoutRecord.putAll(recordStreamMap); + // 获取所有的关联的通道 + List channelList = channelMapper.queryForRecordPlan(startPlanList); + if (channelList.isEmpty()) { + recordStreamMap.clear(); + }else { + // 查找是否已经开启录像, 如果没有则开启录像 + for (CommonGBChannel channel : channelList) { + if (recordStreamMap.get(channel.getGbId()) != null) { + channelMapWithoutRecord.remove(channel.getGbId()); + }else { + // 开启点播, + channelPlayService.play(channel, null, ((code, msg, streamInfo) -> { + if (code == InviteErrorCode.SUCCESS.getCode() && streamInfo != null) { + log.info("[录像] 开启成功, 通道ID: {}", channel.getGbId()); + recordStreamMap.put(channel.getGbId(), streamInfo); + channelMapWithoutRecord.remove(channel.getGbId(), streamInfo); + } + })); + } + } + } + } + // 结束录像 + if(!channelMapWithoutRecord.isEmpty()) { + for (Integer channelId : channelMapWithoutRecord.keySet()) { + StreamInfo streamInfo = channelMapWithoutRecord.get(channelId); + if (streamInfo == null) { + continue; + } + // 查看是否有人观看,存在则不做处理,等待后续自然处理,如果无人观看,则关闭该流 + MediaInfo mediaInfo = mediaServerService.getMediaInfo(streamInfo.getMediaServer(), streamInfo.getApp(), streamInfo.getStream()); + if (mediaInfo.getReaderCount() == null || mediaInfo.getReaderCount() == 0) { + mediaServerService.closeStreams(streamInfo.getMediaServer(), streamInfo.getApp(), streamInfo.getStream()); + log.info("[录像] 停止, 通道ID: {}", channelId); + } + } + } } // 系统启动时 + + @Override + public boolean recording(String app, String stream) { + for (StreamInfo streamInfo : recordStreamMap.values()) { + if (streamInfo.getApp().equals(app) && streamInfo.getStream().equals(stream)) { + return true; + } + } + return false; + } + @Override @Transactional public void add(RecordPlan plan) { diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordPlanMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordPlanMapper.java index 2cdc6468..e9304df0 100644 --- a/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordPlanMapper.java +++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/RecordPlanMapper.java @@ -58,4 +58,7 @@ public interface RecordPlanMapper { @Delete("DELETE FROM wvp_record_plan_item WHERE plan_id = #{planId}") void cleanItems(@Param("planId") Integer planId); + + @Select("select plan_id from wvp_record_plan_item where week_day = #{week} and start >= #{index} and stop <= #{index} group by plan_id") + List queryStart(@Param("week") int week, @Param("index") int index); } diff --git a/web_src/src/components/dialog/editRecordPlan.vue b/web_src/src/components/dialog/editRecordPlan.vue index 1de115cc..4d425779 100644 --- a/web_src/src/components/dialog/editRecordPlan.vue +++ b/web_src/src/components/dialog/editRecordPlan.vue @@ -176,10 +176,8 @@ export default { let start = null; let stop = null; let result = [] - console.log("===================") for (let i = 0; i < weekItem.length; i++) { let item = weekItem[i] - console.log(item) if (item === '1') { // 表示选中 stop = i if (start === null ) {